Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add Qwen(Tongyi) model component #5439

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ dependencies = [
"crewai~=0.86.0",
"ag2",
"pydantic-ai>=0.0.12",
"dashscope>=1.20.14",
]

[project.urls]
Expand Down
3 changes: 3 additions & 0 deletions src/backend/base/langflow/base/models/qwen_constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
QWEN_MODEL_NAMES = ["qwen-plus", "qwen-max", "qwen-turbo","qwen-long"]

MODEL_NAMES = QWEN_MODEL_NAMES
2 changes: 2 additions & 0 deletions src/backend/base/langflow/components/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from .openai import OpenAIModelComponent
from .openrouter import OpenRouterComponent
from .perplexity import PerplexityComponent
from .qwen import QwenModelComponent
from .sambanova import SambaNovaComponent
from .vertexai import ChatVertexAIComponent

Expand All @@ -37,5 +38,6 @@
"OpenRouterComponent",
"PerplexityComponent",
"QianfanChatEndpointComponent",
"QwenModelComponent",
"SambaNovaComponent",
]
53 changes: 53 additions & 0 deletions src/backend/base/langflow/components/models/qwen.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from langchain_community.chat_models.tongyi import ChatTongyi

from langflow.base.models.model import LCModelComponent
from langflow.base.models.qwen_constants import QWEN_MODEL_NAMES
from langflow.field_typing import LanguageModel
from langflow.field_typing.range_spec import RangeSpec
from langflow.io import DropdownInput, SecretStrInput, SliderInput, StrInput


class QwenModelComponent(LCModelComponent):
"""Qwen (Tongyi) model component."""

display_name: str = "Qwen"
description: str = "This component generates text using Alibaba's Qwen (Tongyi) model."
documentation: str = "https://help.aliyun.com/zh/dashscope/developer-reference/api-details"
icon = "Qwen"
name = "QwenModel"

inputs = [
*LCModelComponent._base_inputs,
StrInput(
name="qwen_url",
display_name="Qwen Cloud Base Url",
advanced=True,
value="https://dashscope.aliyuncs.com/compatible-mode/v1",
info="The base URL of the Qwen Cloud API. "
"Defaults to https://dashscope.aliyuncs.com/compatible-mode/v1.",
),
SecretStrInput(
name="qwen_api_key",
display_name="Qwen API Key",
required=True,
password=True,
),
DropdownInput(
name="model_name",
display_name="Model Name",
advanced=False,
options=QWEN_MODEL_NAMES,
value=QWEN_MODEL_NAMES[0],
),
SliderInput(name="top_p", display_name="top_p", value=0.1, range_spec=RangeSpec(min=0, max=1, step=0.01)),
]

def build_model(self) -> LanguageModel:
"""Build the Qwen model."""
qwen_url = self.qwen_url
qwen_api_key = self.qwen_api_key
model_name = self.model_name
top_p = self.top_p

self.model = ChatTongyi(base_url=qwen_url, api_key=qwen_api_key, model=model_name, top_p=top_p)
return self.model
49 changes: 49 additions & 0 deletions src/backend/tests/unit/components/models/test_qwen.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import os

import pytest
from langchain_community.chat_models.tongyi import ChatTongyi
from langflow.base.models.qwen_constants import QWEN_MODEL_NAMES
from langflow.components.models.qwen import QwenModelComponent


@pytest.fixture
def qwen_credentials():
"""Fixture to get Qwen API key from environment variables."""
api_key = os.getenv("QWEN_API_KEY")
if not api_key:
pytest.skip("QWEN_API_KEY environment variable is required.")
return {"api_key": api_key}


@pytest.mark.api_key_required
@pytest.mark.parametrize("model_name", QWEN_MODEL_NAMES)
def test_qwen_different_models(qwen_credentials, model_name):
"""Test different Qwen models with a simple prompt."""
component = QwenModelComponent()
component.qwen_api_key = qwen_credentials["api_key"]
component.model_name = model_name

# Build the model
model = component.build_model()
assert isinstance(model, ChatTongyi)

try:
response = model.invoke("Who are you?")
assert isinstance(response.content, str)
assert len(response.content) > 0
except ValueError as e:
pytest.fail(f"Model {model_name} failed with error: {e!s}")


@pytest.mark.api_key_required
def test_qwen_nonexistent_model(qwen_credentials):
"""Test Qwen with a nonexistent model."""
component = QwenModelComponent()
component.model_name = "nonexistent-model"
component.qwen_api_key = qwen_credentials["api_key"]
model = component.build_model()
assert isinstance(model, ChatTongyi)

# invoke should raise an error with a specific message
with pytest.raises(ValueError, match="status_code: 400 \n code: InvalidParameter \n message: Model not exist."):
model.invoke("Say 'Hello' in Chinese")
2 changes: 1 addition & 1 deletion src/frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 23 additions & 0 deletions src/frontend/src/icons/Qwen/QwenLogo.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
export const SvgQwenLogo = (props) => (
<svg
t="1735087331948"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="4288"
width="20"
height="20"
>
<path
d="M955 607.2L843.6 412.1l47.8-91.6c6.6-8.7 8.3-21.5 5.6-31.8L835.7 178c-4.7-7.3-12.8-11.8-21.5-12H586.3l-51-89.2c-3.6-7-10.5-11.8-18.3-12.7H396.7c-8.9 0.2-15.2 6.7-19.6 14.4l-1.9 3.1-113.8 195.1H152.2c-9-0.2-17.5 4.3-22.3 12L67 400.1c-4 8-4 17.5 0 25.5l113.1 196.7-51 89.2c-4 8-4 17.4 0 25.5l58.1 102c4.7 7.8 13.2 12.7 22.3 12.7h227.8l54.9 95.5c4.2 7.2 11.6 11.9 19.9 12.8h129c8.9-0.2 17.1-5 21.5-12.7L775 750.5h100.4c8.9-0.8 16.9-5.8 21.5-13.5L955 634.3c5.4-8.3 5.4-18.9 0-27.1zM814.1 620L756 512.5 517 933.7l-65.3-107.5H212.8l57.4-104.3H392L153 302.2h125L396.7 90.3l59.7 104.3-61.3 107.5H873l-60.5 106.8 120.3 211H814.1z"
fill="#605BEC"
p-id="4289"
></path>
<path
d="M511.4 660.5l149-238.9H361.7l149.7 238.9z m0 0"
fill="#605BEC"
p-id="4290"
></path>
</svg>
);
1 change: 1 addition & 0 deletions src/frontend/src/icons/Qwen/QwenLogo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions src/frontend/src/icons/Qwen/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import React, { forwardRef } from "react";
import { SvgQwenLogo } from "./QwenLogo";

export const QwenIcon = forwardRef<SVGSVGElement, React.PropsWithChildren<{}>>(
(props, ref) => {
return <SvgQwenLogo ref={ref} {...props} />;
},
);
2 changes: 2 additions & 0 deletions src/frontend/src/utils/styleUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ import { PostgresIcon } from "../icons/Postgres";
import { PythonIcon } from "../icons/Python";
import { QDrantIcon } from "../icons/QDrant";
import { QianFanChatIcon } from "../icons/QianFanChat";
import { QwenIcon } from "../icons/Qwen";
import { RedisIcon } from "../icons/Redis";
import { SambaNovaIcon } from "../icons/SambaNova";
import { SearxIcon } from "../icons/Searx";
Expand Down Expand Up @@ -607,6 +608,7 @@ export const nodeIconsLucide: iconsType = {
RedisSearch: RedisIcon,
PostgresChatMessageHistory: PostgresIcon,
BaiduQianfan: QianFanChatIcon,
Qwen: QwenIcon,
Vectara: VectaraIcon,
ArrowUpToLine: ArrowUpToLine,
Cassandra: CassandraIcon,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ test(
"modelsOpenAI",
"modelsPerplexity",
"modelsQianfan",
"modelsQwen",
"modelsSambaNova",
"modelsVertex AI",
];
Expand Down
51 changes: 33 additions & 18 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading