From 7390bae6f61f9afb321a36bf89dde7acc866be53 Mon Sep 17 00:00:00 2001
From: Sean Hatfield <seanhatfield5@gmail.com>
Date: Thu, 26 Sep 2024 12:55:12 -0700
Subject: [PATCH] Support DeepSeek (#2377)

* add deepseek support

* lint

* update deepseek context length

* add deepseek to onboarding

---------

Co-authored-by: Timothy Carambat <rambat1010@gmail.com>
---
 README.md                                     |   1 +
 .../LLMSelection/DeepSeekOptions/index.jsx    | 100 ++++++++++++++
 frontend/src/media/llmprovider/deepseek.png   | Bin 0 -> 30205 bytes
 .../GeneralSettings/LLMPreference/index.jsx   |  10 ++
 .../Steps/DataHandling/index.jsx              |   6 +
 .../Steps/LLMPreference/index.jsx             |   9 ++
 .../AgentConfig/AgentLLMSelection/index.jsx   |   1 +
 server/models/systemSettings.js               |   4 +
 server/utils/AiProviders/deepseek/index.js    | 127 ++++++++++++++++++
 server/utils/AiProviders/modelMap.js          |   4 +
 server/utils/agents/aibitat/index.js          |   2 +
 .../agents/aibitat/providers/ai-provider.js   |   8 ++
 .../agents/aibitat/providers/deepseek.js      | 118 ++++++++++++++++
 .../utils/agents/aibitat/providers/index.js   |   2 +
 server/utils/agents/index.js                  |   6 +
 server/utils/helpers/customModels.js          |  28 ++++
 server/utils/helpers/index.js                 |   3 +
 server/utils/helpers/updateENV.js             |  11 ++
 18 files changed, 440 insertions(+)
 create mode 100644 frontend/src/components/LLMSelection/DeepSeekOptions/index.jsx
 create mode 100644 frontend/src/media/llmprovider/deepseek.png
 create mode 100644 server/utils/AiProviders/deepseek/index.js
 create mode 100644 server/utils/agents/aibitat/providers/deepseek.js

diff --git a/README.md b/README.md
index d42f6fe91..68c21e4b5 100644
--- a/README.md
+++ b/README.md
@@ -87,6 +87,7 @@ AnythingLLM divides your documents into objects called `workspaces`. A Workspace
 - [Fireworks AI  (chat models)](https://fireworks.ai/)
 - [Perplexity (chat models)](https://www.perplexity.ai/)
 - [OpenRouter (chat models)](https://openrouter.ai/)
+- [DeepSeek (chat models)](https://deepseek.com/)
 - [Mistral](https://mistral.ai/)
 - [Groq](https://groq.com/)
 - [Cohere](https://cohere.com/)
diff --git a/frontend/src/components/LLMSelection/DeepSeekOptions/index.jsx b/frontend/src/components/LLMSelection/DeepSeekOptions/index.jsx
new file mode 100644
index 000000000..5c83d65a9
--- /dev/null
+++ b/frontend/src/components/LLMSelection/DeepSeekOptions/index.jsx
@@ -0,0 +1,100 @@
+import { useState, useEffect } from "react";
+import System from "@/models/system";
+
+export default function DeepSeekOptions({ settings }) {
+  const [inputValue, setInputValue] = useState(settings?.DeepSeekApiKey);
+  const [deepSeekApiKey, setDeepSeekApiKey] = useState(
+    settings?.DeepSeekApiKey
+  );
+
+  return (
+    <div className="flex gap-[36px] mt-1.5">
+      <div className="flex flex-col w-60">
+        <label className="text-white text-sm font-semibold block mb-3">
+          API Key
+        </label>
+        <input
+          type="password"
+          name="DeepSeekApiKey"
+          className="bg-zinc-900 text-white placeholder:text-white/20 text-sm rounded-lg focus:outline-primary-button active:outline-primary-button outline-none block w-full p-2.5"
+          placeholder="DeepSeek API Key"
+          defaultValue={settings?.DeepSeekApiKey ? "*".repeat(20) : ""}
+          required={true}
+          autoComplete="off"
+          spellCheck={false}
+          onChange={(e) => setInputValue(e.target.value)}
+          onBlur={() => setDeepSeekApiKey(inputValue)}
+        />
+      </div>
+      {!settings?.credentialsOnly && (
+        <DeepSeekModelSelection settings={settings} apiKey={deepSeekApiKey} />
+      )}
+    </div>
+  );
+}
+
+function DeepSeekModelSelection({ apiKey, settings }) {
+  const [models, setModels] = useState([]);
+  const [loading, setLoading] = useState(true);
+
+  useEffect(() => {
+    async function findCustomModels() {
+      if (!apiKey) {
+        setModels([]);
+        setLoading(true);
+        return;
+      }
+
+      setLoading(true);
+      const { models } = await System.customModels(
+        "deepseek",
+        typeof apiKey === "boolean" ? null : apiKey
+      );
+      setModels(models || []);
+      setLoading(false);
+    }
+    findCustomModels();
+  }, [apiKey]);
+
+  if (loading) {
+    return (
+      <div className="flex flex-col w-60">
+        <label className="text-white text-sm font-semibold block mb-3">
+          Chat Model Selection
+        </label>
+        <select
+          name="DeepSeekModelPref"
+          disabled={true}
+          className="bg-zinc-900 border-gray-500 text-white text-sm rounded-lg block w-full p-2.5"
+        >
+          <option disabled={true} selected={true}>
+            -- loading available models --
+          </option>
+        </select>
+      </div>
+    );
+  }
+
+  return (
+    <div className="flex flex-col w-60">
+      <label className="text-white text-sm font-semibold block mb-3">
+        Chat Model Selection
+      </label>
+      <select
+        name="DeepSeekModelPref"
+        required={true}
+        className="bg-zinc-900 border-gray-500 text-white text-sm rounded-lg block w-full p-2.5"
+      >
+        {models.map((model) => (
+          <option
+            key={model.id}
+            value={model.id}
+            selected={settings?.DeepSeekModelPref === model.id}
+          >
+            {model.name}
+          </option>
+        ))}
+      </select>
+    </div>
+  );
+}
diff --git a/frontend/src/media/llmprovider/deepseek.png b/frontend/src/media/llmprovider/deepseek.png
new file mode 100644
index 0000000000000000000000000000000000000000..bb8b9f2734e58208c65e477617c7d23ac76c7ada
GIT binary patch
literal 30205
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
D=pWKi

literal 0
HcmV?d00001

diff --git a/frontend/src/pages/GeneralSettings/LLMPreference/index.jsx b/frontend/src/pages/GeneralSettings/LLMPreference/index.jsx
index a70b55cc8..6b041c117 100644
--- a/frontend/src/pages/GeneralSettings/LLMPreference/index.jsx
+++ b/frontend/src/pages/GeneralSettings/LLMPreference/index.jsx
@@ -25,6 +25,7 @@ import TextGenWebUILogo from "@/media/llmprovider/text-generation-webui.png";
 import CohereLogo from "@/media/llmprovider/cohere.png";
 import LiteLLMLogo from "@/media/llmprovider/litellm.png";
 import AWSBedrockLogo from "@/media/llmprovider/bedrock.png";
+import DeepSeekLogo from "@/media/llmprovider/deepseek.png";
 
 import PreLoader from "@/components/Preloader";
 import OpenAiOptions from "@/components/LLMSelection/OpenAiOptions";
@@ -48,6 +49,7 @@ import KoboldCPPOptions from "@/components/LLMSelection/KoboldCPPOptions";
 import TextGenWebUIOptions from "@/components/LLMSelection/TextGenWebUIOptions";
 import LiteLLMOptions from "@/components/LLMSelection/LiteLLMOptions";
 import AWSBedrockLLMOptions from "@/components/LLMSelection/AwsBedrockLLMOptions";
+import DeepSeekOptions from "@/components/LLMSelection/DeepSeekOptions";
 
 import LLMItem from "@/components/LLMSelection/LLMItem";
 import { CaretUpDown, MagnifyingGlass, X } from "@phosphor-icons/react";
@@ -211,6 +213,14 @@ export const AVAILABLE_LLM_PROVIDERS = [
     description: "Run LiteLLM's OpenAI compatible proxy for various LLMs.",
     requiredConfig: ["LiteLLMBasePath"],
   },
+  {
+    name: "DeepSeek",
+    value: "deepseek",
+    logo: DeepSeekLogo,
+    options: (settings) => <DeepSeekOptions settings={settings} />,
+    description: "Run DeepSeek's powerful LLMs.",
+    requiredConfig: ["DeepSeekApiKey"],
+  },
   {
     name: "Generic OpenAI",
     value: "generic-openai",
diff --git a/frontend/src/pages/OnboardingFlow/Steps/DataHandling/index.jsx b/frontend/src/pages/OnboardingFlow/Steps/DataHandling/index.jsx
index b739d502a..39d10e77f 100644
--- a/frontend/src/pages/OnboardingFlow/Steps/DataHandling/index.jsx
+++ b/frontend/src/pages/OnboardingFlow/Steps/DataHandling/index.jsx
@@ -20,6 +20,7 @@ import KoboldCPPLogo from "@/media/llmprovider/koboldcpp.png";
 import TextGenWebUILogo from "@/media/llmprovider/text-generation-webui.png";
 import LiteLLMLogo from "@/media/llmprovider/litellm.png";
 import AWSBedrockLogo from "@/media/llmprovider/bedrock.png";
+import DeepSeekLogo from "@/media/llmprovider/deepseek.png";
 
 import CohereLogo from "@/media/llmprovider/cohere.png";
 import ZillizLogo from "@/media/vectordbs/zilliz.png";
@@ -196,6 +197,11 @@ export const LLM_SELECTION_PRIVACY = {
     ],
     logo: AWSBedrockLogo,
   },
+  deepseek: {
+    name: "DeepSeek",
+    description: ["Your model and chat contents are visible to DeepSeek"],
+    logo: DeepSeekLogo,
+  },
 };
 
 export 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 52996b695..81b26f66a 100644
--- a/frontend/src/pages/OnboardingFlow/Steps/LLMPreference/index.jsx
+++ b/frontend/src/pages/OnboardingFlow/Steps/LLMPreference/index.jsx
@@ -20,6 +20,7 @@ import KoboldCPPLogo from "@/media/llmprovider/koboldcpp.png";
 import TextGenWebUILogo from "@/media/llmprovider/text-generation-webui.png";
 import LiteLLMLogo from "@/media/llmprovider/litellm.png";
 import AWSBedrockLogo from "@/media/llmprovider/bedrock.png";
+import DeepSeekLogo from "@/media/llmprovider/deepseek.png";
 
 import CohereLogo from "@/media/llmprovider/cohere.png";
 import OpenAiOptions from "@/components/LLMSelection/OpenAiOptions";
@@ -43,6 +44,7 @@ import KoboldCPPOptions from "@/components/LLMSelection/KoboldCPPOptions";
 import TextGenWebUIOptions from "@/components/LLMSelection/TextGenWebUIOptions";
 import LiteLLMOptions from "@/components/LLMSelection/LiteLLMOptions";
 import AWSBedrockLLMOptions from "@/components/LLMSelection/AwsBedrockLLMOptions";
+import DeepSeekOptions from "@/components/LLMSelection/DeepSeekOptions";
 
 import LLMItem from "@/components/LLMSelection/LLMItem";
 import System from "@/models/system";
@@ -186,6 +188,13 @@ const LLMS = [
     options: (settings) => <LiteLLMOptions settings={settings} />,
     description: "Run LiteLLM's OpenAI compatible proxy for various LLMs.",
   },
+  {
+    name: "DeepSeek",
+    value: "deepseek",
+    logo: DeepSeekLogo,
+    options: (settings) => <DeepSeekOptions settings={settings} />,
+    description: "Run DeepSeek's powerful LLMs.",
+  },
   {
     name: "Generic OpenAI",
     value: "generic-openai",
diff --git a/frontend/src/pages/WorkspaceSettings/AgentConfig/AgentLLMSelection/index.jsx b/frontend/src/pages/WorkspaceSettings/AgentConfig/AgentLLMSelection/index.jsx
index 00a0aef95..97193d5a0 100644
--- a/frontend/src/pages/WorkspaceSettings/AgentConfig/AgentLLMSelection/index.jsx
+++ b/frontend/src/pages/WorkspaceSettings/AgentConfig/AgentLLMSelection/index.jsx
@@ -23,6 +23,7 @@ const ENABLED_PROVIDERS = [
   "generic-openai",
   "bedrock",
   "fireworksai",
+  "deepseek",
   // TODO: More agent support.
   // "cohere",         // Has tool calling and will need to build explicit support
   // "huggingface"     // Can be done but already has issues with no-chat templated. Needs to be tested.
diff --git a/server/models/systemSettings.js b/server/models/systemSettings.js
index e3012ec4e..c51000191 100644
--- a/server/models/systemSettings.js
+++ b/server/models/systemSettings.js
@@ -506,6 +506,10 @@ const SystemSettings = {
 
       // VoyageAi API Keys
       VoyageAiApiKey: !!process.env.VOYAGEAI_API_KEY,
+
+      // DeepSeek API Keys
+      DeepSeekApiKey: !!process.env.DEEPSEEK_API_KEY,
+      DeepSeekModelPref: process.env.DEEPSEEK_MODEL_PREF,
     };
   },
 
diff --git a/server/utils/AiProviders/deepseek/index.js b/server/utils/AiProviders/deepseek/index.js
new file mode 100644
index 000000000..5ef4c9a1c
--- /dev/null
+++ b/server/utils/AiProviders/deepseek/index.js
@@ -0,0 +1,127 @@
+const { NativeEmbedder } = require("../../EmbeddingEngines/native");
+const {
+  handleDefaultStreamResponseV2,
+} = require("../../helpers/chat/responses");
+const { MODEL_MAP } = require("../modelMap");
+
+class DeepSeekLLM {
+  constructor(embedder = null, modelPreference = null) {
+    if (!process.env.DEEPSEEK_API_KEY)
+      throw new Error("No DeepSeek API key was set.");
+    const { OpenAI: OpenAIApi } = require("openai");
+
+    this.openai = new OpenAIApi({
+      apiKey: process.env.DEEPSEEK_API_KEY,
+      baseURL: "https://api.deepseek.com/v1",
+    });
+    this.model =
+      modelPreference || process.env.DEEPSEEK_MODEL_PREF || "deepseek-chat";
+    this.limits = {
+      history: this.promptWindowLimit() * 0.15,
+      system: this.promptWindowLimit() * 0.15,
+      user: this.promptWindowLimit() * 0.7,
+    };
+
+    this.embedder = embedder ?? new NativeEmbedder();
+    this.defaultTemp = 0.7;
+  }
+
+  #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 "streamGetChatCompletion" in this;
+  }
+
+  static promptWindowLimit(modelName) {
+    return MODEL_MAP.deepseek[modelName] ?? 8192;
+  }
+
+  promptWindowLimit() {
+    return MODEL_MAP.deepseek[this.model] ?? 8192;
+  }
+
+  async isValidChatCompletionModel(modelName = "") {
+    const models = await this.openai.models.list().catch(() => ({ data: [] }));
+    return models.data.some((model) => model.id === modelName);
+  }
+
+  constructPrompt({
+    systemPrompt = "",
+    contextTexts = [],
+    chatHistory = [],
+    userPrompt = "",
+  }) {
+    const prompt = {
+      role: "system",
+      content: `${systemPrompt}${this.#appendContext(contextTexts)}`,
+    };
+    return [prompt, ...chatHistory, { role: "user", content: userPrompt }];
+  }
+
+  async getChatCompletion(messages = null, { temperature = 0.7 }) {
+    if (!(await this.isValidChatCompletionModel(this.model)))
+      throw new Error(
+        `DeepSeek chat: ${this.model} is not valid for chat completion!`
+      );
+
+    const result = await this.openai.chat.completions
+      .create({
+        model: this.model,
+        messages,
+        temperature,
+      })
+      .catch((e) => {
+        throw new Error(e.message);
+      });
+
+    if (!result.hasOwnProperty("choices") || result.choices.length === 0)
+      return null;
+    return result.choices[0].message.content;
+  }
+
+  async streamGetChatCompletion(messages = null, { temperature = 0.7 }) {
+    if (!(await this.isValidChatCompletionModel(this.model)))
+      throw new Error(
+        `DeepSeek chat: ${this.model} is not valid for chat completion!`
+      );
+
+    const streamRequest = await this.openai.chat.completions.create({
+      model: this.model,
+      stream: true,
+      messages,
+      temperature,
+    });
+    return streamRequest;
+  }
+
+  handleStream(response, stream, responseProps) {
+    return handleDefaultStreamResponseV2(response, stream, responseProps);
+  }
+
+  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 = {
+  DeepSeekLLM,
+};
diff --git a/server/utils/AiProviders/modelMap.js b/server/utils/AiProviders/modelMap.js
index b7604b69a..99d78dc14 100644
--- a/server/utils/AiProviders/modelMap.js
+++ b/server/utils/AiProviders/modelMap.js
@@ -53,6 +53,10 @@ const MODEL_MAP = {
     "gpt-4": 8_192,
     "gpt-4-32k": 32_000,
   },
+  deepseek: {
+    "deepseek-chat": 128_000,
+    "deepseek-coder": 128_000,
+  },
 };
 
 module.exports = { MODEL_MAP };
diff --git a/server/utils/agents/aibitat/index.js b/server/utils/agents/aibitat/index.js
index 90d6069c0..1d356f00a 100644
--- a/server/utils/agents/aibitat/index.js
+++ b/server/utils/agents/aibitat/index.js
@@ -783,6 +783,8 @@ ${this.getHistory({ to: route.to })
         return new Providers.AWSBedrockProvider({});
       case "fireworksai":
         return new Providers.FireworksAIProvider({ model: config.model });
+      case "deepseek":
+        return new Providers.DeepSeekProvider({ model: config.model });
 
       default:
         throw new Error(
diff --git a/server/utils/agents/aibitat/providers/ai-provider.js b/server/utils/agents/aibitat/providers/ai-provider.js
index 23d107647..3a144ec6c 100644
--- a/server/utils/agents/aibitat/providers/ai-provider.js
+++ b/server/utils/agents/aibitat/providers/ai-provider.js
@@ -174,6 +174,14 @@ class Provider {
           apiKey: process.env.TEXT_GEN_WEB_UI_API_KEY ?? "not-used",
           ...config,
         });
+      case "deepseek":
+        return new ChatOpenAI({
+          configuration: {
+            baseURL: "https://api.deepseek.com/v1",
+          },
+          apiKey: process.env.DEEPSEEK_API_KEY ?? null,
+          ...config,
+        });
       default:
         throw new Error(`Unsupported provider ${provider} for this task.`);
     }
diff --git a/server/utils/agents/aibitat/providers/deepseek.js b/server/utils/agents/aibitat/providers/deepseek.js
new file mode 100644
index 000000000..aec1ee39e
--- /dev/null
+++ b/server/utils/agents/aibitat/providers/deepseek.js
@@ -0,0 +1,118 @@
+const OpenAI = require("openai");
+const Provider = require("./ai-provider.js");
+const InheritMultiple = require("./helpers/classes.js");
+const UnTooled = require("./helpers/untooled.js");
+const { toValidNumber } = require("../../../http/index.js");
+
+class DeepSeekProvider extends InheritMultiple([Provider, UnTooled]) {
+  model;
+
+  constructor(config = {}) {
+    super();
+    const { model = "deepseek-chat" } = config;
+    const client = new OpenAI({
+      baseURL: "https://api.deepseek.com/v1",
+      apiKey: process.env.DEEPSEEK_API_KEY ?? null,
+      maxRetries: 3,
+    });
+
+    this._client = client;
+    this.model = model;
+    this.verbose = true;
+    this.maxTokens = process.env.DEEPSEEK_MAX_TOKENS
+      ? toValidNumber(process.env.DEEPSEEK_MAX_TOKENS, 1024)
+      : 1024;
+  }
+
+  get client() {
+    return this._client;
+  }
+
+  async #handleFunctionCallChat({ messages = [] }) {
+    return await this.client.chat.completions
+      .create({
+        model: this.model,
+        temperature: 0,
+        messages,
+        max_tokens: this.maxTokens,
+      })
+      .then((result) => {
+        if (!result.hasOwnProperty("choices"))
+          throw new Error("DeepSeek chat: No results!");
+        if (result.choices.length === 0)
+          throw new Error("DeepSeek chat: No results length!");
+        return result.choices[0].message.content;
+      })
+      .catch((_) => {
+        return null;
+      });
+  }
+
+  /**
+   * Create a completion based on the received messages.
+   *
+   * @param messages A list of messages to send to the API.
+   * @param functions
+   * @returns The completion.
+   */
+  async complete(messages, functions = null) {
+    try {
+      let completion;
+      if (functions.length > 0) {
+        const { toolCall, text } = await this.functionCall(
+          messages,
+          functions,
+          this.#handleFunctionCallChat.bind(this)
+        );
+
+        if (toolCall !== null) {
+          this.providerLog(`Valid tool call found - running ${toolCall.name}.`);
+          this.deduplicator.trackRun(toolCall.name, toolCall.arguments);
+          return {
+            result: null,
+            functionCall: {
+              name: toolCall.name,
+              arguments: toolCall.arguments,
+            },
+            cost: 0,
+          };
+        }
+        completion = { content: text };
+      }
+
+      if (!completion?.content) {
+        this.providerLog(
+          "Will assume chat completion without tool call inputs."
+        );
+        const response = await this.client.chat.completions.create({
+          model: this.model,
+          messages: this.cleanMsgs(messages),
+        });
+        completion = response.choices[0].message;
+      }
+
+      // The UnTooled class inherited Deduplicator is mostly useful to prevent the agent
+      // from calling the exact same function over and over in a loop within a single chat exchange
+      // _but_ we should enable it to call previously used tools in a new chat interaction.
+      this.deduplicator.reset("runs");
+      return {
+        result: completion.content,
+        cost: 0,
+      };
+    } catch (error) {
+      throw error;
+    }
+  }
+
+  /**
+   * Get the cost of the completion.
+   *
+   * @param _usage The completion to get the cost for.
+   * @returns The cost of the completion.
+   */
+  getCost(_usage) {
+    return 0;
+  }
+}
+
+module.exports = DeepSeekProvider;
diff --git a/server/utils/agents/aibitat/providers/index.js b/server/utils/agents/aibitat/providers/index.js
index dd95bb54a..086e0ccf0 100644
--- a/server/utils/agents/aibitat/providers/index.js
+++ b/server/utils/agents/aibitat/providers/index.js
@@ -14,6 +14,7 @@ const PerplexityProvider = require("./perplexity.js");
 const TextWebGenUiProvider = require("./textgenwebui.js");
 const AWSBedrockProvider = require("./bedrock.js");
 const FireworksAIProvider = require("./fireworksai.js");
+const DeepSeekProvider = require("./deepseek.js");
 
 module.exports = {
   OpenAIProvider,
@@ -28,6 +29,7 @@ module.exports = {
   OpenRouterProvider,
   MistralProvider,
   GenericOpenAiProvider,
+  DeepSeekProvider,
   PerplexityProvider,
   TextWebGenUiProvider,
   AWSBedrockProvider,
diff --git a/server/utils/agents/index.js b/server/utils/agents/index.js
index 389d9d71b..3936f9388 100644
--- a/server/utils/agents/index.js
+++ b/server/utils/agents/index.js
@@ -162,6 +162,10 @@ class AgentHandler {
             "FireworksAI API Key must be provided to use agents."
           );
         break;
+      case "deepseek":
+        if (!process.env.DEEPSEEK_API_KEY)
+          throw new Error("DeepSeek API Key must be provided to use agents.");
+        break;
 
       default:
         throw new Error(
@@ -206,6 +210,8 @@ class AgentHandler {
         return null;
       case "fireworksai":
         return null;
+      case "deepseek":
+        return "deepseek-chat";
       default:
         return "unknown";
     }
diff --git a/server/utils/helpers/customModels.js b/server/utils/helpers/customModels.js
index a25896ef4..f061d35ff 100644
--- a/server/utils/helpers/customModels.js
+++ b/server/utils/helpers/customModels.js
@@ -18,6 +18,7 @@ const SUPPORT_CUSTOM_MODELS = [
   "litellm",
   "elevenlabs-tts",
   "groq",
+  "deepseek",
 ];
 
 async function getCustomModels(provider = "", apiKey = null, basePath = null) {
@@ -53,6 +54,8 @@ async function getCustomModels(provider = "", apiKey = null, basePath = null) {
       return await getElevenLabsModels(apiKey);
     case "groq":
       return await getGroqAiModels(apiKey);
+    case "deepseek":
+      return await getDeepSeekModels(apiKey);
     default:
       return { models: [], error: "Invalid provider for custom models" };
   }
@@ -419,6 +422,31 @@ async function getElevenLabsModels(apiKey = null) {
   return { models, error: null };
 }
 
+async function getDeepSeekModels(apiKey = null) {
+  const { OpenAI: OpenAIApi } = require("openai");
+  const openai = new OpenAIApi({
+    apiKey: apiKey || process.env.DEEPSEEK_API_KEY,
+    baseURL: "https://api.deepseek.com/v1",
+  });
+  const models = await openai.models
+    .list()
+    .then((results) => results.data)
+    .then((models) =>
+      models.map((model) => ({
+        id: model.id,
+        name: model.id,
+        organization: model.owned_by,
+      }))
+    )
+    .catch((e) => {
+      console.error(`DeepSeek:listModels`, e.message);
+      return [];
+    });
+
+  if (models.length > 0 && !!apiKey) process.env.DEEPSEEK_API_KEY = apiKey;
+  return { models, error: null };
+}
+
 module.exports = {
   getCustomModels,
 };
diff --git a/server/utils/helpers/index.js b/server/utils/helpers/index.js
index 71e352c30..6f2dd79d4 100644
--- a/server/utils/helpers/index.js
+++ b/server/utils/helpers/index.js
@@ -159,6 +159,9 @@ function getLLMProvider({ provider = null, model = null } = {}) {
     case "bedrock":
       const { AWSBedrockLLM } = require("../AiProviders/bedrock");
       return new AWSBedrockLLM(embedder, model);
+    case "deepseek":
+      const { DeepSeekLLM } = require("../AiProviders/deepseek");
+      return new DeepSeekLLM(embedder, model);
     default:
       throw new Error(
         `ENV: No valid LLM_PROVIDER value found in environment! Using ${process.env.LLM_PROVIDER}`
diff --git a/server/utils/helpers/updateENV.js b/server/utils/helpers/updateENV.js
index 7b70efa23..e898d4b09 100644
--- a/server/utils/helpers/updateENV.js
+++ b/server/utils/helpers/updateENV.js
@@ -501,6 +501,16 @@ const KEY_MAPPING = {
     envKey: "TTS_PIPER_VOICE_MODEL",
     checks: [],
   },
+
+  // DeepSeek Options
+  DeepSeekApiKey: {
+    envKey: "DEEPSEEK_API_KEY",
+    checks: [isNotEmpty],
+  },
+  DeepSeekModelPref: {
+    envKey: "DEEPSEEK_MODEL_PREF",
+    checks: [isNotEmpty],
+  },
 };
 
 function isNotEmpty(input = "") {
@@ -602,6 +612,7 @@ function supportedLLM(input = "") {
     "litellm",
     "generic-openai",
     "bedrock",
+    "deepseek",
   ].includes(input);
   return validSelection ? null : `${input} is not a valid LLM provider.`;
 }
-- 
GitLab