feat: Add DeepSeek Model component (#5443)

* feat: Add DeepSeek component

* Adiciona DeepseekModelComponent ao __init__.py

* [autofix.ci] apply automated fixes

* Add DeepSeek icon and update component files

* Add DeepSeek icon and update all related files

* [autofix.ci] apply automated fixes

* Change DeepSeek icon color to blue (#080c34)

* [autofix.ci] apply automated fixes

* Revert DeepSeek icon color to black

* [autofix.ci] apply automated fixes

* remove: name parameter from DeepSeekModel to avoid backwards compatibility issues

* test: add unit tests for DeepSeek model component with mocks

* fix: correct formatting issues in DeepSeek model tests

* feat: update DeepSeek icon color to #4c6cfc

* fix: make DeepSeek API key field required

* fix: format SecretStrInput to comply with line length limit in DeepSeekModelComponent

* feat: add dark mode support for component icon

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Edwin Jose <edwin.jose@datastax.com>
This commit is contained in:
Raphael Valdetaro 2025-01-17 14:45:39 -03:00 • committed by GitHub
commit 656f9f30db
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 339 additions and 0 deletions

View file

@ -4,6 +4,7 @@ from .anthropic import AnthropicModelComponent
from .azure_openai import AzureChatOpenAIComponent
from .baidu_qianfan_chat import QianfanChatEndpointComponent
from .cohere import CohereComponent
from .deepseek import DeepSeekModelComponent
from .google_generative_ai import GoogleGenerativeAIComponent
from .groq import GroqModel
from .huggingface import HuggingFaceEndpointsComponent
@ -26,6 +27,7 @@ __all__ = [
"ChatOllamaComponent",
"ChatVertexAIComponent",
"CohereComponent",
"DeepSeekModelComponent",
"GoogleGenerativeAIComponent",
"GroqModel",
"HuggingFaceEndpointsComponent",

View file

@ -0,0 +1,135 @@
import requests
from pydantic.v1 import SecretStr
from typing_extensions import override
from langflow.base.models.model import LCModelComponent
from langflow.field_typing import LanguageModel
from langflow.field_typing.range_spec import RangeSpec
from langflow.inputs import BoolInput, DictInput, DropdownInput, IntInput, SecretStrInput, SliderInput, StrInput
DEEPSEEK_MODELS = ["deepseek-chat"]
class DeepSeekModelComponent(LCModelComponent):
display_name = "DeepSeek"
description = "Generate text using DeepSeek LLMs."
icon = "DeepSeek"
inputs = [
*LCModelComponent._base_inputs,
IntInput(
name="max_tokens",
display_name="Max Tokens",
advanced=True,
info="Maximum number of tokens to generate. Set to 0 for unlimited.",
range_spec=RangeSpec(min=0, max=128000),
),
DictInput(
name="model_kwargs",
display_name="Model Kwargs",
advanced=True,
info="Additional keyword arguments to pass to the model.",
),
BoolInput(
name="json_mode",
display_name="JSON Mode",
advanced=True,
info="If True, it will output JSON regardless of passing a schema.",
),
DropdownInput(
name="model_name",
display_name="Model Name",
info="DeepSeek model to use",
options=DEEPSEEK_MODELS,
value="deepseek-chat",
refresh_button=True,
),
StrInput(
name="api_base",
display_name="DeepSeek API Base",
advanced=True,
info="Base URL for API requests. Defaults to https://api.deepseek.com",
value="https://api.deepseek.com",
),
SecretStrInput(
name="api_key",
display_name="DeepSeek API Key",
info="The DeepSeek API Key",
advanced=False,
required=True,
),
SliderInput(
name="temperature",
display_name="Temperature",
info="Controls randomness in responses",
value=1.0,
range_spec=RangeSpec(min=0, max=2, step=0.01),
),
IntInput(
name="seed",
display_name="Seed",
info="The seed controls the reproducibility of the job.",
advanced=True,
value=1,
),
]
def get_models(self) -> list[str]:
if not self.api_key:
return DEEPSEEK_MODELS
url = f"{self.api_base}/models"
headers = {"Authorization": f"Bearer {self.api_key}", "Accept": "application/json"}
try:
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
model_list = response.json()
return [model["id"] for model in model_list.get("data", [])]
except requests.RequestException as e:
self.status = f"Error fetching models: {e}"
return DEEPSEEK_MODELS
@override
def update_build_config(self, build_config: dict, field_value: str, field_name: str | None = None):
if field_name in {"api_key", "api_base", "model_name"}:
models = self.get_models()
build_config["model_name"]["options"] = models
return build_config
def build_model(self) -> LanguageModel:
try:
from langchain_openai import ChatOpenAI
except ImportError as e:
msg = "langchain-openai not installed. Please install with `pip install langchain-openai`"
raise ImportError(msg) from e
api_key = SecretStr(self.api_key).get_secret_value() if self.api_key else None
output = ChatOpenAI(
model=self.model_name,
temperature=self.temperature if self.temperature is not None else 0.1,
max_tokens=self.max_tokens or None,
model_kwargs=self.model_kwargs or {},
base_url=self.api_base,
api_key=api_key,
streaming=self.stream if hasattr(self, "stream") else False,
seed=self.seed,
)
if self.json_mode:
output = output.bind(response_format={"type": "json_object"})
return output
def _get_exception_message(self, e: Exception):
"""Get message from DeepSeek API exception."""
try:
from openai import BadRequestError
if isinstance(e, BadRequestError):
message = e.body.get("message")
if message:
return message
except ImportError:
pass
return None