Skip to content

Commit ca07ddb

Browse files
authored
fix: models/tongyi has global side effect on base_url (langgenius#2473)
* fix: global side effect * chore: bump version * chore: add .venv to .difyignore
1 parent 843176f commit ca07ddb

File tree

9 files changed

+108
-41
lines changed

9 files changed

+108
-41
lines changed

models/tongyi/.difyignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.venv

models/tongyi/manifest.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,5 @@ resource:
2525
model:
2626
enabled: false
2727
type: plugin
28-
version: 0.1.19
28+
version: 0.1.20
2929
created_at: "2024-12-10T16:13:50.29298939+08:00"

models/tongyi/models/_common.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from typing import Mapping
2+
13
from dashscope.common.error import (
24
AuthenticationError,
35
InvalidParameter,
@@ -16,6 +18,23 @@
1618
InvokeServerUnavailableError,
1719
)
1820

21+
DEFAULT_HTTP_BASE_ADDRESS = "https://dashscope.aliyuncs.com/api/v1"
22+
DEFAULT_WS_BASE_ADDRESS = "wss://dashscope.aliyuncs.com/api-ws/v1/inference"
23+
INTL_HTTP_BASE_ADDRESS = "https://dashscope-intl.aliyuncs.com/api/v1"
24+
INTL_WS_BASE_ADDRESS = "wss://dashscope-intl.aliyuncs.com/api-ws/v1/inference"
25+
26+
27+
def get_http_base_address(credentials: Mapping[str, str]) -> str:
28+
if credentials.get("use_international_endpoint", "false") == "true":
29+
return INTL_HTTP_BASE_ADDRESS
30+
return DEFAULT_HTTP_BASE_ADDRESS
31+
32+
33+
def get_ws_base_address(credentials: Mapping[str, str]) -> str:
34+
if credentials.get("use_international_endpoint", "false") == "true":
35+
return INTL_WS_BASE_ADDRESS
36+
return DEFAULT_WS_BASE_ADDRESS
37+
1938

2039
class _CommonTongyi:
2140
@staticmethod

models/tongyi/models/llm/llm.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
)
6262
from dify_plugin.interfaces.model.large_language_model import LargeLanguageModel
6363
from openai import OpenAI
64+
from models._common import get_http_base_address
6465
from ..constant import BURY_POINT_HEADER
6566

6667
logger = logging.getLogger(__name__)
@@ -238,7 +239,7 @@ def _generate(
238239
if common_force_condition or model.startswith(("qwq-", "qvq-")):
239240
incremental_output = True
240241

241-
base_address = "https://dashscope-intl.aliyuncs.com/api/v1" if credentials.get("use_international_endpoint") == "true" else None
242+
base_address = get_http_base_address(credentials)
242243

243244
# The parameter `enable_omni_output_audio_url` must be set to true when using the Omni model in non-streaming mode.
244245
if model.startswith("qwen3-omni-") and not stream:

models/tongyi/models/rerank/rerank.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
InvokeServerUnavailableError,
2020
)
2121
from dify_plugin.interfaces.model.rerank_model import RerankModel
22+
from models._common import get_http_base_address
2223
from ..constant import BURY_POINT_HEADER
2324

2425
class GTERerankModel(RerankModel):
@@ -50,11 +51,16 @@ def _invoke(
5051
"""
5152
if len(docs) == 0:
5253
return RerankResult(model=model, docs=docs)
53-
if credentials.get("use_international_endpoint", "false") == "true":
54-
dashscope.base_http_api_url = "https://dashscope-intl.aliyuncs.com/api/v1"
55-
dashscope.api_key = credentials["dashscope_api_key"]
54+
http_base_address = get_http_base_address(credentials)
5655
response = dashscope.TextReRank.call(
57-
query=query, headers=BURY_POINT_HEADER, documents=docs, model=model, top_n=top_n, return_documents=True
56+
query=query,
57+
headers=BURY_POINT_HEADER,
58+
documents=docs,
59+
model=model,
60+
top_n=top_n,
61+
return_documents=True,
62+
api_key=credentials["dashscope_api_key"],
63+
base_address=http_base_address,
5864
)
5965
rerank_documents = []
6066
if not response.output:

models/tongyi/models/speech2text/speech2text.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
from pydub import AudioSegment
44
import tempfile
55
from typing import IO, Optional
6-
import dashscope
76
from dify_plugin import OAICompatSpeech2TextModel
87
from dashscope.audio.asr import *
8+
from models._common import get_ws_base_address
99
from ..constant import BURY_POINT_HEADER
1010

1111
class TongyiSpeech2TextModel(OAICompatSpeech2TextModel):
@@ -24,9 +24,7 @@ def _invoke(self, model: str, credentials: dict, file: IO[bytes], user: Optional
2424
:return: text for given audio file
2525
"""
2626
try:
27-
if credentials.get("use_international_endpoint", "false") == "true":
28-
dashscope.base_http_api_url = "https://dashscope-intl.aliyuncs.com/api/v1"
29-
dashscope.api_key = credentials["dashscope_api_key"]
27+
ws_base_address = get_ws_base_address(credentials)
3028
file.seek(0)
3129
audio = AudioSegment.from_file(file)
3230
sample_rate = audio.frame_rate
@@ -42,7 +40,12 @@ def _invoke(self, model: str, credentials: dict, file: IO[bytes], user: Optional
4240
sample_rate=int(sample_rate),
4341
callback=None,
4442
)
45-
result = recognition.call(file=file_path, headers=BURY_POINT_HEADER)
43+
result = recognition.call(
44+
file=file_path,
45+
headers=BURY_POINT_HEADER,
46+
api_key=credentials["dashscope_api_key"],
47+
base_address=ws_base_address,
48+
)
4649
sentence_list = result.get_sentence()
4750
if sentence_list is None:
4851
return ''

models/tongyi/models/text_embedding/text_embedding.py

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from dify_plugin.entities.model.text_embedding import EmbeddingUsage, MultiModalContent, MultiModalContentType, MultiModalEmbeddingResult, TextEmbeddingResult
1010
from dify_plugin.errors.model import CredentialsValidateFailedError
1111
from dify_plugin.interfaces.model.text_embedding_model import TextEmbeddingModel
12-
from models._common import _CommonTongyi
12+
from models._common import _CommonTongyi, get_http_base_address
1313
from ..constant import BURY_POINT_HEADER
1414

1515
vision_models = dict()
@@ -37,8 +37,7 @@ def _invoke(
3737
:param input_type: input type
3838
:return: embeddings result
3939
"""
40-
if credentials.get("use_international_endpoint", "false") == "true":
41-
dashscope.base_http_api_url = "https://dashscope-intl.aliyuncs.com/api/v1"
40+
http_base_address = get_http_base_address(credentials)
4241
credentials_kwargs = self._to_credential_kwargs(credentials)
4342
context_size = self._get_context_size(model, credentials)
4443
max_chunks = self._get_max_chunks(model, credentials)
@@ -57,7 +56,10 @@ def _invoke(
5756
_iter = range(0, len(inputs), max_chunks)
5857
for i in _iter:
5958
(embeddings_batch, embedding_used_tokens) = self.embed_documents(
60-
credentials_kwargs=credentials_kwargs, model=model, texts=inputs[i : i + max_chunks]
59+
credentials_kwargs=credentials_kwargs,
60+
model=model,
61+
texts=inputs[i : i + max_chunks],
62+
base_address=http_base_address,
6163
)
6264
used_tokens += embedding_used_tokens
6365
batched_embeddings += embeddings_batch
@@ -90,12 +92,23 @@ def validate_credentials(self, model: str, credentials: dict) -> None:
9092
"""
9193
try:
9294
credentials_kwargs = self._to_credential_kwargs(credentials)
93-
self.embed_documents(credentials_kwargs=credentials_kwargs, model=model, texts=["ping"])
95+
http_base_address = get_http_base_address(credentials)
96+
self.embed_documents(
97+
credentials_kwargs=credentials_kwargs,
98+
model=model,
99+
texts=["ping"],
100+
base_address=http_base_address,
101+
)
94102
except Exception as ex:
95103
raise CredentialsValidateFailedError(str(ex))
96104

97105
@staticmethod
98-
def embed_documents(credentials_kwargs: dict, model: str, texts: list[str]) -> tuple[list[list[float]], int]:
106+
def embed_documents(
107+
credentials_kwargs: dict,
108+
model: str,
109+
texts: list[str],
110+
base_address: str,
111+
) -> tuple[list[list[float]], int]:
99112
"""Call out to Tongyi's embedding endpoint.
100113
101114
Args:
@@ -111,7 +124,12 @@ def embed_documents(credentials_kwargs: dict, model: str, texts: list[str]) -> t
111124
# transfer and call embed_multimodal_documents
112125
if TongyiTextEmbeddingModel._is_vision_model(model):
113126
documents = [MultiModalContent(content_type=MultiModalContentType.TEXT, content=text) for text in texts]
114-
return TongyiTextEmbeddingModel.embed_multimodal_documents(credentials_kwargs, model, documents)
127+
return TongyiTextEmbeddingModel.embed_multimodal_documents(
128+
credentials_kwargs,
129+
model,
130+
documents,
131+
base_address,
132+
)
115133

116134
embeddings = []
117135
embedding_used_tokens = 0
@@ -124,14 +142,16 @@ def call_embedding_api(text):
124142
api_key=credentials_kwargs["dashscope_api_key"],
125143
model=model,
126144
input=[{"text": text}],
145+
base_address=base_address,
127146
)
128147
else:
129148
return dashscope.TextEmbedding.call(
130149
api_key=credentials_kwargs["dashscope_api_key"],
131150
model=model,
132151
input=text,
133152
headers=BURY_POINT_HEADER,
134-
text_type="document"
153+
text_type="document",
154+
base_address=base_address,
135155
)
136156
except Exception as e:
137157
# Return the exception to be handled by the caller
@@ -236,11 +256,13 @@ def _invoke_multimodal(
236256
:param input_type: input type
237257
:return: embeddings result
238258
"""
239-
if credentials.get("use_international_endpoint", "false") == "true":
240-
dashscope.base_http_api_url = "https://dashscope-intl.aliyuncs.com/api/v1"
259+
http_base_address = get_http_base_address(credentials)
241260
credentials_kwargs = self._to_credential_kwargs(credentials)
242261
(embeddings_batch, embedding_used_tokens) = self.embed_multimodal_documents(
243-
credentials_kwargs=credentials_kwargs, model=model, documents=documents
262+
credentials_kwargs=credentials_kwargs,
263+
model=model,
264+
documents=documents,
265+
base_address=http_base_address,
244266
)
245267
usage = self._calc_response_usage(model=model, credentials=credentials, tokens=embedding_used_tokens)
246268
return MultiModalEmbeddingResult(
@@ -250,7 +272,12 @@ def _invoke_multimodal(
250272
)
251273

252274
@staticmethod
253-
def embed_multimodal_documents(credentials_kwargs: dict, model: str, documents: list[MultiModalContent]) -> tuple[list[list[float]], int]:
275+
def embed_multimodal_documents(
276+
credentials_kwargs: dict,
277+
model: str,
278+
documents: list[MultiModalContent],
279+
base_address: str,
280+
) -> tuple[list[list[float]], int]:
254281
"""Call out to Tongyi's embedding endpoint.
255282
256283
Args:
@@ -292,7 +319,8 @@ def call_embedding_api(input):
292319
return dashscope.MultiModalEmbedding.call(
293320
api_key=credentials_kwargs["dashscope_api_key"],
294321
model=model,
295-
input=[input],
322+
input=[input],
323+
base_address=base_address,
296324
)
297325
except Exception as e:
298326
# Return the exception to be handled by the caller

models/tongyi/models/tts/tts.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
import threading
22
from queue import Queue
33
from typing import Any, Optional
4-
import dashscope
54
from dashscope import SpeechSynthesizer
65
from dashscope.api_entities.dashscope_response import SpeechSynthesisResponse
76
from dashscope.audio.tts import ResultCallback, SpeechSynthesisResult
87
from dify_plugin.errors.model import CredentialsValidateFailedError, InvokeBadRequestError
98
from dify_plugin.interfaces.model.tts_model import TTSModel
10-
from models._common import _CommonTongyi
9+
from models._common import _CommonTongyi, get_ws_base_address
1110
from ..constant import BURY_POINT_HEADER
1211

1312
class TongyiText2SpeechModel(_CommonTongyi, TTSModel):
@@ -66,11 +65,12 @@ def _tts_invoke_streaming(self, model: str, credentials: dict, content_text: str
6665
"""
6766
word_limit = self._get_model_word_limit(model, credentials)
6867
audio_type = self._get_model_audio_type(model, credentials)
68+
ws_base_address = get_ws_base_address(credentials)
6969
try:
7070
audio_queue: Queue = Queue()
7171
callback = Callback(queue=audio_queue)
7272

73-
def invoke_remote(content, v, api_key, cb, at, wl):
73+
def invoke_remote(content, v, api_key, cb, at, wl, base_address):
7474
if len(content) < word_limit:
7575
sentences = [content]
7676
else:
@@ -85,11 +85,20 @@ def invoke_remote(content, v, api_key, cb, at, wl):
8585
format=at,
8686
word_timestamp_enabled=True,
8787
phoneme_timestamp_enabled=True,
88+
base_address=base_address,
8889
)
8990

9091
threading.Thread(
9192
target=invoke_remote,
92-
args=(content_text, voice, credentials.get("dashscope_api_key"), callback, audio_type, word_limit),
93+
args=(
94+
content_text,
95+
voice,
96+
credentials.get("dashscope_api_key"),
97+
callback,
98+
audio_type,
99+
word_limit,
100+
ws_base_address,
101+
),
93102
).start()
94103
while True:
95104
audio = audio_queue.get()
@@ -110,15 +119,15 @@ def _process_sentence(sentence: str, credentials: dict, voice: str, audio_type:
110119
:param audio_type: audio file type
111120
:return: text translated to audio file
112121
"""
113-
if credentials.get("use_international_endpoint", "false") == "true":
114-
dashscope.base_http_api_url = "https://dashscope-intl.aliyuncs.com/api/v1"
115-
response = dashscope.audio.tts.SpeechSynthesizer.call(
122+
ws_base_address = get_ws_base_address(credentials)
123+
response = SpeechSynthesizer.call(
116124
model=voice,
117125
sample_rate=48000,
118126
api_key=credentials.get("dashscope_api_key"),
119127
text=sentence.strip(),
120128
headers=BURY_POINT_HEADER,
121129
format=audio_type,
130+
base_address=ws_base_address,
122131
)
123132
if isinstance(response.get_audio_data(), bytes):
124133
return response.get_audio_data()

models/tongyi/uv.lock

Lines changed: 10 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)