mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-11 03:38:38 +00:00
Merge 91a5125874 into 64d8d7f8cb
This commit is contained in:
commit
4a9945dcc5
10 changed files with 226 additions and 0 deletions
|
|
@ -654,6 +654,7 @@ snowflake_models: Set = set()
|
|||
gradient_ai_models: Set = set()
|
||||
llama_models: Set = set()
|
||||
nscale_models: Set = set()
|
||||
siliconflow_models: Set = set()
|
||||
nebius_models: Set = set()
|
||||
nebius_embedding_models: Set = set()
|
||||
aiml_models: Set = set()
|
||||
|
|
@ -847,6 +848,8 @@ def add_known_models(model_cost_map: Optional[Dict] = None):
|
|||
llama_models.add(key)
|
||||
elif value.get("litellm_provider") == "nscale":
|
||||
nscale_models.add(key)
|
||||
elif value.get("litellm_provider") == "siliconflow":
|
||||
siliconflow_models.add(key)
|
||||
elif value.get("litellm_provider") == "azure_ai":
|
||||
azure_ai_models.add(key)
|
||||
elif value.get("litellm_provider") == "voyage":
|
||||
|
|
@ -1062,6 +1065,7 @@ model_list = list(
|
|||
| llama_models
|
||||
| featherless_ai_models
|
||||
| nscale_models
|
||||
| siliconflow_models
|
||||
| deepgram_models
|
||||
| elevenlabs_models
|
||||
| dashscope_models
|
||||
|
|
@ -1164,6 +1168,7 @@ models_by_provider: dict = {
|
|||
"gradient_ai": gradient_ai_models,
|
||||
"meta_llama": llama_models,
|
||||
"nscale": nscale_models,
|
||||
"siliconflow": siliconflow_models,
|
||||
"featherless_ai": featherless_ai_models,
|
||||
"deepgram": deepgram_models,
|
||||
"elevenlabs": elevenlabs_models,
|
||||
|
|
@ -1858,6 +1863,9 @@ if TYPE_CHECKING:
|
|||
PerplexityChatConfig as _PerplexityChatConfig,
|
||||
)
|
||||
from .llms.nscale.chat.transformation import NscaleConfig as _NscaleConfig
|
||||
from .llms.siliconflow.chat.transformation import (
|
||||
SiliconFlowConfig as _SiliconFlowConfig,
|
||||
)
|
||||
from .llms.watsonx.chat.transformation import (
|
||||
IBMWatsonXChatConfig as _IBMWatsonXChatConfig,
|
||||
)
|
||||
|
|
@ -1892,6 +1900,7 @@ if TYPE_CHECKING:
|
|||
AzureOpenAIO1Config: Type[_AzureOpenAIO1Config]
|
||||
PerplexityChatConfig: Type[_PerplexityChatConfig]
|
||||
NscaleConfig: Type[_NscaleConfig]
|
||||
SiliconFlowConfig: Type[_SiliconFlowConfig]
|
||||
IBMWatsonXChatConfig: Type[_IBMWatsonXChatConfig]
|
||||
IBMWatsonXAIConfig: Type[_IBMWatsonXAIConfig]
|
||||
LiteLLMProxyChatConfig: Type[_LiteLLMProxyChatConfig]
|
||||
|
|
|
|||
|
|
@ -287,6 +287,7 @@ LLM_CONFIG_NAMES = (
|
|||
"LMStudioChatConfig",
|
||||
"LmStudioEmbeddingConfig",
|
||||
"NscaleConfig",
|
||||
"SiliconFlowConfig",
|
||||
"PerplexityChatConfig",
|
||||
"AzureOpenAIO1Config",
|
||||
"IBMWatsonXAIConfig",
|
||||
|
|
@ -1101,6 +1102,10 @@ _LLM_CONFIGS_IMPORT_MAP = {
|
|||
"LmStudioEmbeddingConfig",
|
||||
),
|
||||
"NscaleConfig": (".llms.nscale.chat.transformation", "NscaleConfig"),
|
||||
"SiliconFlowConfig": (
|
||||
".llms.siliconflow.chat.transformation",
|
||||
"SiliconFlowConfig",
|
||||
),
|
||||
"PerplexityChatConfig": (
|
||||
".llms.perplexity.chat.transformation",
|
||||
"PerplexityChatConfig",
|
||||
|
|
|
|||
|
|
@ -639,6 +639,7 @@ LITELLM_CHAT_PROVIDERS = [
|
|||
"meta_llama",
|
||||
"featherless_ai",
|
||||
"nscale",
|
||||
"siliconflow",
|
||||
"nebius",
|
||||
"dashscope",
|
||||
"modelscope",
|
||||
|
|
@ -798,6 +799,8 @@ openai_compatible_endpoints: List = [
|
|||
"api.llama.com/compat/v1/",
|
||||
"api.featherless.ai/v1",
|
||||
"inference.api.nscale.com/v1",
|
||||
"api.siliconflow.com/v1",
|
||||
"api.siliconflow.cn/v1",
|
||||
"api.studio.nebius.ai/v1",
|
||||
"https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
|
||||
"https://api-inference.modelscope.cn/v1",
|
||||
|
|
@ -866,6 +869,7 @@ openai_compatible_providers: List = [
|
|||
"libertai", # LibertAI - JSON-configured provider
|
||||
"featherless_ai",
|
||||
"nscale",
|
||||
"siliconflow",
|
||||
"nebius",
|
||||
"dashscope",
|
||||
"modelscope",
|
||||
|
|
|
|||
|
|
@ -331,6 +331,12 @@ def get_llm_provider(
|
|||
elif endpoint == litellm.NscaleConfig.API_BASE_URL:
|
||||
custom_llm_provider = "nscale"
|
||||
dynamic_api_key = litellm.NscaleConfig.get_api_key()
|
||||
elif endpoint == "api.siliconflow.com/v1":
|
||||
custom_llm_provider = "siliconflow"
|
||||
dynamic_api_key = litellm.SiliconFlowConfig.get_api_key()
|
||||
elif endpoint == "api.siliconflow.cn/v1":
|
||||
custom_llm_provider = "siliconflow"
|
||||
dynamic_api_key = litellm.SiliconFlowConfig.get_api_key()
|
||||
elif endpoint == "dashscope-intl.aliyuncs.com/compatible-mode/v1":
|
||||
custom_llm_provider = "dashscope"
|
||||
dynamic_api_key = get_secret_str("DASHSCOPE_API_KEY")
|
||||
|
|
@ -921,6 +927,13 @@ def _get_openai_compatible_provider_info(
|
|||
) = litellm.NscaleConfig()._get_openai_compatible_provider_info(
|
||||
api_base=api_base, api_key=api_key
|
||||
)
|
||||
elif custom_llm_provider == "siliconflow":
|
||||
(
|
||||
api_base,
|
||||
dynamic_api_key,
|
||||
) = litellm.SiliconFlowConfig()._get_openai_compatible_provider_info(
|
||||
api_base=api_base, api_key=api_key
|
||||
)
|
||||
elif custom_llm_provider == "heroku":
|
||||
(
|
||||
api_base,
|
||||
|
|
|
|||
|
|
@ -271,6 +271,8 @@ def get_supported_openai_params(
|
|||
return litellm.PerplexityChatConfig().get_supported_openai_params(model=model)
|
||||
elif custom_llm_provider == "nscale":
|
||||
return litellm.NscaleConfig().get_supported_openai_params(model=model)
|
||||
elif custom_llm_provider == "siliconflow":
|
||||
return litellm.SiliconFlowConfig().get_supported_openai_params(model=model)
|
||||
elif custom_llm_provider == "anyscale":
|
||||
return [
|
||||
"temperature",
|
||||
|
|
|
|||
64
litellm/llms/siliconflow/chat/transformation.py
Normal file
64
litellm/llms/siliconflow/chat/transformation.py
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
from typing import Optional, Tuple
|
||||
|
||||
from litellm.llms.openai.chat.gpt_transformation import OpenAIGPTConfig
|
||||
from litellm.secret_managers.main import get_secret_str
|
||||
|
||||
|
||||
class SiliconFlowConfig(OpenAIGPTConfig):
|
||||
"""
|
||||
Reference: SiliconFlow is OpenAI compatible.
|
||||
|
||||
API Key: SILICONFLOW_API_KEY
|
||||
Default API Base: https://api.siliconflow.com/v1
|
||||
|
||||
Users on the China mainland endpoint can set
|
||||
SILICONFLOW_API_BASE=https://api.siliconflow.cn/v1
|
||||
"""
|
||||
|
||||
API_BASE_URL = "https://api.siliconflow.com/v1"
|
||||
|
||||
@property
|
||||
def custom_llm_provider(self) -> Optional[str]:
|
||||
return "siliconflow"
|
||||
|
||||
@staticmethod
|
||||
def get_api_key(api_key: Optional[str] = None) -> Optional[str]:
|
||||
return api_key or get_secret_str("SILICONFLOW_API_KEY")
|
||||
|
||||
@staticmethod
|
||||
def get_api_base(api_base: Optional[str] = None) -> Optional[str]:
|
||||
return (
|
||||
api_base
|
||||
or get_secret_str("SILICONFLOW_API_BASE")
|
||||
or SiliconFlowConfig.API_BASE_URL
|
||||
)
|
||||
|
||||
def _get_openai_compatible_provider_info(
|
||||
self, api_base: Optional[str], api_key: Optional[str]
|
||||
) -> Tuple[Optional[str], Optional[str]]:
|
||||
resolved_api_base = SiliconFlowConfig.get_api_base(api_base)
|
||||
resolved_api_key = SiliconFlowConfig.get_api_key(api_key)
|
||||
return resolved_api_base, resolved_api_key
|
||||
|
||||
def get_supported_openai_params(self, model: str) -> list:
|
||||
return [
|
||||
"max_tokens",
|
||||
"max_completion_tokens",
|
||||
"n",
|
||||
"temperature",
|
||||
"top_p",
|
||||
"seed",
|
||||
"stream",
|
||||
"stream_options",
|
||||
"logprobs",
|
||||
"top_logprobs",
|
||||
"frequency_penalty",
|
||||
"presence_penalty",
|
||||
"response_format",
|
||||
"stop",
|
||||
"logit_bias",
|
||||
"tools",
|
||||
"tool_choice",
|
||||
"parallel_tool_calls",
|
||||
"user",
|
||||
]
|
||||
|
|
@ -3455,6 +3455,7 @@ class LlmProviders(str, Enum):
|
|||
GRADIENT_AI = "gradient_ai"
|
||||
LLAMA = "meta_llama"
|
||||
NSCALE = "nscale"
|
||||
SILICONFLOW = "siliconflow"
|
||||
PG_VECTOR = "pg_vector"
|
||||
S3_VECTORS = "s3_vectors"
|
||||
HELICONE = "helicone"
|
||||
|
|
|
|||
|
|
@ -8586,6 +8586,10 @@ class ProviderConfigManager:
|
|||
),
|
||||
LlmProviders.GRADIENT_AI: (lambda: litellm.GradientAIConfig(), False),
|
||||
LlmProviders.NSCALE: (lambda: litellm.NscaleConfig(), False),
|
||||
LlmProviders.SILICONFLOW: (
|
||||
lambda: litellm.SiliconFlowConfig(),
|
||||
False,
|
||||
),
|
||||
LlmProviders.HEROKU: (lambda: litellm.HerokuChatConfig(), False),
|
||||
LlmProviders.OCI: (lambda: litellm.OCIChatConfig(), False),
|
||||
LlmProviders.HYPERBOLIC: (lambda: litellm.HyperbolicChatConfig(), False),
|
||||
|
|
|
|||
|
|
@ -32,6 +32,24 @@
|
|||
}
|
||||
},
|
||||
"providers": {
|
||||
"siliconflow": {
|
||||
"display_name": "SiliconFlow (`siliconflow`)",
|
||||
"url": "https://docs.litellm.ai/docs/providers/siliconflow",
|
||||
"endpoints": {
|
||||
"chat_completions": true,
|
||||
"messages": true,
|
||||
"responses": true,
|
||||
"embeddings": false,
|
||||
"image_generations": false,
|
||||
"audio_transcriptions": false,
|
||||
"audio_speech": false,
|
||||
"moderations": false,
|
||||
"batches": false,
|
||||
"rerank": false,
|
||||
"a2a": true,
|
||||
"interactions": true
|
||||
}
|
||||
},
|
||||
"a2a": {
|
||||
"display_name": "A2A (Agent-to-Agent) (`a2a`)",
|
||||
"url": "https://docs.litellm.ai/docs/providers/a2a",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,106 @@
|
|||
import os
|
||||
import sys
|
||||
from unittest.mock import patch
|
||||
|
||||
sys.path.insert(0, os.path.abspath("../../../../.."))
|
||||
|
||||
import litellm
|
||||
from litellm import get_llm_provider, get_supported_openai_params
|
||||
from litellm.llms.siliconflow.chat.transformation import SiliconFlowConfig
|
||||
|
||||
|
||||
class TestSiliconFlowConfig:
|
||||
def setup_method(self):
|
||||
self.config = SiliconFlowConfig()
|
||||
|
||||
def test_custom_llm_provider(self):
|
||||
assert self.config.custom_llm_provider == "siliconflow"
|
||||
|
||||
def test_get_api_key(self):
|
||||
assert self.config.get_api_key("test-key") == "test-key"
|
||||
|
||||
with patch(
|
||||
"litellm.llms.siliconflow.chat.transformation.get_secret_str",
|
||||
return_value="env-key",
|
||||
):
|
||||
assert self.config.get_api_key() == "env-key"
|
||||
|
||||
with patch.dict(os.environ, {"SILICONFLOW_API_KEY": "env-key"}, clear=False):
|
||||
assert self.config.get_api_key() == "env-key"
|
||||
|
||||
def test_get_api_base_precedence(self):
|
||||
# Explicit argument wins over everything.
|
||||
assert (
|
||||
self.config.get_api_base("https://custom-base.com/v1")
|
||||
== "https://custom-base.com/v1"
|
||||
)
|
||||
|
||||
# SILICONFLOW_API_BASE override (e.g. the China mainland endpoint).
|
||||
with patch(
|
||||
"litellm.llms.siliconflow.chat.transformation.get_secret_str",
|
||||
return_value="https://api.siliconflow.cn/v1",
|
||||
):
|
||||
assert self.config.get_api_base() == "https://api.siliconflow.cn/v1"
|
||||
|
||||
# Falls back to the default global endpoint.
|
||||
with patch(
|
||||
"litellm.llms.siliconflow.chat.transformation.get_secret_str",
|
||||
return_value=None,
|
||||
):
|
||||
assert self.config.get_api_base() == SiliconFlowConfig.API_BASE_URL
|
||||
assert SiliconFlowConfig.API_BASE_URL == "https://api.siliconflow.com/v1"
|
||||
|
||||
def test_get_openai_compatible_provider_info(self):
|
||||
def fake_secret(name, *args, **kwargs):
|
||||
return "sk-secret" if name == "SILICONFLOW_API_KEY" else None
|
||||
|
||||
with patch(
|
||||
"litellm.llms.siliconflow.chat.transformation.get_secret_str",
|
||||
side_effect=fake_secret,
|
||||
):
|
||||
api_base, api_key = self.config._get_openai_compatible_provider_info(
|
||||
api_base=None, api_key=None
|
||||
)
|
||||
assert api_base == "https://api.siliconflow.com/v1"
|
||||
assert api_key == "sk-secret"
|
||||
|
||||
def test_supported_params_include_tools(self):
|
||||
params = self.config.get_supported_openai_params(
|
||||
model="deepseek-ai/DeepSeek-V3"
|
||||
)
|
||||
for expected in ("temperature", "stream", "tools", "tool_choice"):
|
||||
assert expected in params
|
||||
|
||||
|
||||
class TestSiliconFlowProviderResolution:
|
||||
def test_get_llm_provider_resolves_prefixed_model(self):
|
||||
with patch.dict(os.environ, {"SILICONFLOW_API_KEY": "sk-secret"}, clear=False):
|
||||
model, provider, api_key, api_base = get_llm_provider(
|
||||
model="siliconflow/deepseek-ai/DeepSeek-V3"
|
||||
)
|
||||
assert model == "deepseek-ai/DeepSeek-V3"
|
||||
assert provider == "siliconflow"
|
||||
assert api_key == "sk-secret"
|
||||
assert api_base == "https://api.siliconflow.com/v1"
|
||||
|
||||
def test_get_llm_provider_detects_provider_from_api_base(self):
|
||||
_, provider, _, _ = get_llm_provider(
|
||||
model="deepseek-ai/DeepSeek-V3",
|
||||
api_base="https://api.siliconflow.com/v1",
|
||||
api_key="sk-secret",
|
||||
)
|
||||
assert provider == "siliconflow"
|
||||
|
||||
def test_get_supported_openai_params_routes_to_config(self):
|
||||
params = get_supported_openai_params(
|
||||
model="deepseek-ai/DeepSeek-V3", custom_llm_provider="siliconflow"
|
||||
)
|
||||
assert params is not None
|
||||
assert "tools" in params
|
||||
|
||||
def test_provider_registered_in_enum_and_lists(self):
|
||||
from litellm.types.utils import LlmProviders
|
||||
|
||||
assert LlmProviders.SILICONFLOW.value == "siliconflow"
|
||||
assert "siliconflow" in litellm.openai_compatible_providers
|
||||
assert "api.siliconflow.com/v1" in litellm.openai_compatible_endpoints
|
||||
Loading…
Add table
Reference in a new issue