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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
KXWyR~`u!j1AJS0(

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.`;
 }