From 5fc3bd38b086c11a3bf9b9d68a7a72f5fa597b58 Mon Sep 17 00:00:00 2001 From: Magicbook1108 Date: Mon, 2 Mar 2026 15:37:42 +0800 Subject: [PATCH] Feat: Support siliconflow.com (#13308) ### What problem does this PR solve? Feat: Support siliconflow.com ### Type of change - [x] New Feature (non-breaking change which adds functionality) --- api/apps/llm_app.py | 23 +- conf/llm_factories.json | 457 ++++++++++++++++++ rag/llm/embedding_model.py | 9 +- rag/llm/rerank_model.py | 9 +- web/src/hooks/use-llm-request.tsx | 1 + web/src/locales/bg.ts | 2 + web/src/locales/de.ts | 2 + web/src/locales/en.ts | 2 + web/src/locales/es.ts | 2 + web/src/locales/fr.ts | 2 + web/src/locales/id.ts | 2 + web/src/locales/it.ts | 2 + web/src/locales/ja.ts | 2 + web/src/locales/pt-br.ts | 2 + web/src/locales/ru.ts | 2 + web/src/locales/vi.ts | 2 + web/src/locales/zh-traditional.ts | 2 + web/src/locales/zh.ts | 2 + .../user-setting/setting-model/hooks.tsx | 13 +- .../modal/api-key-modal/index.tsx | 9 +- 20 files changed, 530 insertions(+), 17 deletions(-) diff --git a/api/apps/llm_app.py b/api/apps/llm_app.py index 9d2fed8026..6fa9a8e3d8 100644 --- a/api/apps/llm_app.py +++ b/api/apps/llm_app.py @@ -34,7 +34,7 @@ from rag.llm import EmbeddingModel, ChatModel, RerankModel, CvModel, TTSModel, O def factories(): try: fac = get_allowed_llm_factories() - fac = [f.to_dict() for f in fac if f.name not in ["Youdao", "FastEmbed", "BAAI", "Builtin"]] + fac = [f.to_dict() for f in fac if f.name not in ["Youdao", "FastEmbed", "BAAI", "Builtin", "siliconflow_intl"]] llms = LLMService.get_all() mdl_types = {} for m in llms: @@ -64,13 +64,22 @@ async def set_api_key(): # test if api key works chat_passed, embd_passed, rerank_passed = False, False, False factory = req["llm_factory"] + base_url = req.get("base_url", "") + source_factory = req.get("source_fid", factory) extra = {"provider": factory} timeout_seconds = int(os.environ.get("LLM_TIMEOUT_SECONDS", 10)) + source_llms = list(LLMService.query(fid=source_factory)) + if not source_llms: + msg = f"No models configured for {factory} (source: {source_factory})." + if req.get("verify", False): + return get_json_result(data={"message": msg, "success": False}) + return get_data_error_result(message=msg) + msg = "" - for llm in LLMService.query(fid=factory): + for llm in source_llms: if not embd_passed and llm.model_type == LLMType.EMBEDDING.value: assert factory in EmbeddingModel, f"Embedding model from {factory} is not supported yet." - mdl = EmbeddingModel[factory](req["api_key"], llm.llm_name, base_url=req.get("base_url")) + mdl = EmbeddingModel[factory](req["api_key"], llm.llm_name, base_url=base_url) try: arr, tc = await asyncio.wait_for( asyncio.to_thread(mdl.encode, ["Test if the api key is available"]), @@ -83,7 +92,7 @@ async def set_api_key(): msg += f"\nFail to access embedding model({llm.llm_name}) using this api key." + str(e) elif not chat_passed and llm.model_type == LLMType.CHAT.value: assert factory in ChatModel, f"Chat model from {factory} is not supported yet." - mdl = ChatModel[factory](req["api_key"], llm.llm_name, base_url=req.get("base_url"), **extra) + mdl = ChatModel[factory](req["api_key"], llm.llm_name, base_url=base_url, **extra) try: m, tc = await asyncio.wait_for( mdl.async_chat( @@ -100,7 +109,7 @@ async def set_api_key(): msg += f"\nFail to access model({llm.fid}/{llm.llm_name}) using this api key." + str(e) elif not rerank_passed and llm.model_type == LLMType.RERANK.value: assert factory in RerankModel, f"Re-rank model from {factory} is not supported yet." - mdl = RerankModel[factory](req["api_key"], llm.llm_name, base_url=req.get("base_url")) + mdl = RerankModel[factory](req["api_key"], llm.llm_name, base_url=base_url) try: arr, tc = await asyncio.wait_for( asyncio.to_thread(mdl.similarity, "What's the weather?", ["Is it sunny today?"]), @@ -122,12 +131,12 @@ async def set_api_key(): if msg: return get_data_error_result(message=msg) - llm_config = {"api_key": req["api_key"], "api_base": req.get("base_url", "")} + llm_config = {"api_key": req["api_key"], "api_base": base_url} for n in ["model_type", "llm_name"]: if n in req: llm_config[n] = req[n] - for llm in LLMService.query(fid=factory): + for llm in source_llms: llm_config["max_tokens"] = llm.max_tokens if not TenantLLMService.filter_update([TenantLLM.tenant_id == current_user.id, TenantLLM.llm_factory == factory, TenantLLM.llm_name == llm.llm_name], llm_config): TenantLLMService.save( diff --git a/conf/llm_factories.json b/conf/llm_factories.json index 89c089444c..8f898da902 100644 --- a/conf/llm_factories.json +++ b/conf/llm_factories.json @@ -3245,6 +3245,463 @@ } ] }, + { + "name": "siliconflow_intl", + "logo": "", + "tags": "LLM,TEXT EMBEDDING,TEXT RE-RANK,IMAGE2TEXT,TTS", + "status": "1", + "rank": "781", + "llm": [ + { + "llm_name": "meta-llama/Meta-Llama-3.1-8B-Instruct", + "tags": "LLM,CHAT,33k", + "max_tokens": 33000, + "model_type": "chat", + "is_tools": false + }, + { + "llm_name": "MiniMaxAI/MiniMax-M2.5", + "tags": "LLM,CHAT,197k", + "max_tokens": 197000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "zai-org/GLM-5", + "tags": "LLM,CHAT,205k", + "max_tokens": 205000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "stepfun-ai/Step-3.5-Flash", + "tags": "LLM,CHAT,262k", + "max_tokens": 262000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "moonshotai/Kimi-K2.5", + "tags": "LLM,CHAT,262k", + "max_tokens": 262000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "MiniMaxAI/MiniMax-M2.1", + "tags": "LLM,CHAT,197k", + "max_tokens": 197000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "zai-org/GLM-4.7", + "tags": "LLM,CHAT,205k", + "max_tokens": 205000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "deepseek-ai/DeepSeek-V3.2", + "tags": "LLM,CHAT,164k", + "max_tokens": 164000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "deepseek-ai/DeepSeek-V3.2-Exp", + "tags": "LLM,CHAT,164k", + "max_tokens": 164000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "zai-org/GLM-4.6V", + "tags": "LLM,CHAT,131k", + "max_tokens": 131000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "deepseek-ai/DeepSeek-V3.1-Terminus", + "tags": "LLM,CHAT,164k", + "max_tokens": 164000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "deepseek-ai/DeepSeek-V3.1", + "tags": "LLM,CHAT,164k", + "max_tokens": 164000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "deepseek-ai/DeepSeek-V3", + "tags": "LLM,CHAT,164k", + "max_tokens": 164000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "deepseek-ai/DeepSeek-R1", + "tags": "LLM,CHAT,154k", + "max_tokens": 154000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "nex-agi/DeepSeek-V3.1-Nex-N1", + "tags": "LLM,CHAT,164k", + "max_tokens": 164000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "Qwen/Qwen3-VL-32B-Instruct", + "tags": "LLM,CHAT,262k", + "max_tokens": 262000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "Qwen/Qwen3-VL-32B-Thinking", + "tags": "LLM,CHAT,262k", + "max_tokens": 262000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "zai-org/GLM-4.5V", + "tags": "LLM,CHAT,66k", + "max_tokens": 66000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "inclusionAI/Ling-mini-2.0", + "tags": "LLM,CHAT,131k", + "max_tokens": 131000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "inclusionAI/Ring-flash-2.0", + "tags": "LLM,CHAT,131k", + "max_tokens": 131000, + "model_type": "chat", + "is_tools": false + }, + { + "llm_name": "inclusionAI/Ling-flash-2.0", + "tags": "LLM,CHAT,131k", + "max_tokens": 131000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "tencent/Hunyuan-MT-7B", + "tags": "LLM,CHAT,32k", + "max_tokens": 32000, + "model_type": "chat", + "is_tools": false + }, + { + "llm_name": "Qwen/Qwen3-Omni-30B-A3B-Captioner", + "tags": "LLM,CHAT,131k", + "max_tokens": 131000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "Qwen/Qwen3-Omni-30B-A3B-Thinking", + "tags": "LLM,CHAT,131k", + "max_tokens": 131000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "Qwen/Qwen3-Omni-30B-A3B-Instruct", + "tags": "LLM,CHAT,65k", + "max_tokens": 65000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "Qwen/Qwen3-Next-80B-A3B-Thinking", + "tags": "LLM,CHAT,262k", + "max_tokens": 262000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "Qwen/Qwen3-Next-80B-A3B-Instruct", + "tags": "LLM,CHAT,262k", + "max_tokens": 262000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "Qwen/Qwen3-Coder-480B-A35B-Instruct", + "tags": "LLM,CHAT,262k", + "max_tokens": 262000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "Qwen/Qwen3-Coder-30B-A3B-Instruct", + "tags": "LLM,CHAT,262k", + "max_tokens": 262000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "Qwen/Qwen3-30B-A3B-Thinking-2507", + "tags": "LLM,CHAT,262k", + "max_tokens": 262000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "Qwen/Qwen3-30B-A3B-Instruct-2507", + "tags": "LLM,CHAT,262k", + "max_tokens": 262000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "Qwen/Qwen3-235B-A22B-Instruct-2507", + "tags": "LLM,CHAT,262k", + "max_tokens": 262000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "Qwen/Qwen3-235B-A22B-Thinking-2507", + "tags": "LLM,CHAT,262k", + "max_tokens": 262000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "ByteDance-Seed/Seed-OSS-36B-Instruct", + "tags": "LLM,CHAT,262k", + "max_tokens": 262000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "baidu/ERNIE-4.5-300B-A47B", + "tags": "LLM,CHAT,131k", + "max_tokens": 131000, + "model_type": "chat", + "is_tools": false + }, + { + "llm_name": "tencent/Hunyuan-A13B-Instruct", + "tags": "LLM,CHAT,131k", + "max_tokens": 131000, + "model_type": "chat", + "is_tools": false + }, + { + "llm_name": "moonshotai/Kimi-K2-Instruct", + "tags": "LLM,CHAT,131k", + "max_tokens": 131000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "Qwen/Qwen3-32B", + "tags": "LLM,CHAT,131k", + "max_tokens": 131000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "Qwen/Qwen3-14B", + "tags": "LLM,CHAT,131k", + "max_tokens": 131000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "Qwen/Qwen3-8B", + "tags": "LLM,CHAT,131k", + "max_tokens": 131000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "Qwen/Qwen3-Reranker-8B", + "tags": "LLM,RE-RANK,33k", + "max_tokens": 33000, + "model_type": "rerank", + "is_tools": false + }, + { + "llm_name": "Qwen/Qwen3-Embedding-8B", + "tags": "LLM,EMBEDDING,33k", + "max_tokens": 33000, + "model_type": "embedding", + "is_tools": false + }, + { + "llm_name": "Qwen/Qwen3-Reranker-4B", + "tags": "LLM,RE-RANK,33k", + "max_tokens": 33000, + "model_type": "rerank", + "is_tools": false + }, + { + "llm_name": "Qwen/Qwen3-Embedding-4B", + "tags": "LLM,EMBEDDING,33k", + "max_tokens": 33000, + "model_type": "embedding", + "is_tools": false + }, + { + "llm_name": "Qwen/Qwen3-Reranker-0.6B", + "tags": "LLM,RE-RANK,33k", + "max_tokens": 33000, + "model_type": "rerank", + "is_tools": false + }, + { + "llm_name": "Qwen/Qwen3-Embedding-0.6B", + "tags": "LLM,EMBEDDING,33k", + "max_tokens": 33000, + "model_type": "embedding", + "is_tools": false + }, + { + "llm_name": "THUDM/GLM-Z1-32B-0414", + "tags": "LLM,CHAT,131k", + "max_tokens": 131000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "THUDM/GLM-4-32B-0414", + "tags": "LLM,CHAT,33k", + "max_tokens": 33000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "THUDM/GLM-Z1-9B-0414", + "tags": "LLM,CHAT,131k", + "max_tokens": 131000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "THUDM/GLM-4-9B-0414", + "tags": "LLM,CHAT,33k", + "max_tokens": 33000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "Qwen/Qwen2.5-VL-32B-Instruct", + "tags": "LLM,CHAT,131k", + "max_tokens": 131000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "Qwen/QwQ-32B", + "tags": "LLM,CHAT,131k", + "max_tokens": 131000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "Qwen/Qwen2.5-VL-72B-Instruct", + "tags": "LLM,CHAT,131k", + "max_tokens": 131000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "Qwen/Qwen2.5-VL-7B-Instruct", + "tags": "LLM,CHAT,33k", + "max_tokens": 33000, + "model_type": "chat", + "is_tools": false + }, + { + "llm_name": "deepseek-ai/DeepSeek-R1-Distill-Qwen-32B", + "tags": "LLM,CHAT,131k", + "max_tokens": 131000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "deepseek-ai/DeepSeek-R1-Distill-Qwen-14B", + "tags": "LLM,CHAT,131k", + "max_tokens": 131000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "Qwen/Qwen2.5-Coder-32B-Instruct", + "tags": "LLM,CHAT,33k", + "max_tokens": 33000, + "model_type": "chat", + "is_tools": false + }, + { + "llm_name": "Qwen/Qwen2.5-72B-Instruct-128K", + "tags": "LLM,CHAT,131k", + "max_tokens": 131000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "deepseek-ai/deepseek-vl2", + "tags": "LLM,CHAT,4k", + "max_tokens": 4000, + "model_type": "chat", + "is_tools": false + }, + { + "llm_name": "Qwen/Qwen2.5-72B-Instruct", + "tags": "LLM,CHAT,33k", + "max_tokens": 33000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "Qwen/Qwen2.5-32B-Instruct", + "tags": "LLM,CHAT,33k", + "max_tokens": 33000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "Qwen/Qwen2.5-14B-Instruct", + "tags": "LLM,CHAT,33k", + "max_tokens": 33000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "Qwen/Qwen2.5-7B-Instruct", + "tags": "LLM,CHAT,33k", + "max_tokens": 33000, + "model_type": "chat", + "is_tools": true + }, + { + "llm_name": "IndexTeam/IndexTTS-2", + "tags": "TTS", + "max_tokens": 1000, + "model_type": "tts", + "is_tools": false + } + ] + }, { "name": "PPIO", "logo": "", diff --git a/rag/llm/embedding_model.py b/rag/llm/embedding_model.py index 699b8be336..79dc96accf 100644 --- a/rag/llm/embedding_model.py +++ b/rag/llm/embedding_model.py @@ -770,14 +770,17 @@ class SILICONFLOWEmbed(Base): _FACTORY_NAME = "SILICONFLOW" def __init__(self, key, model_name, base_url="https://api.siliconflow.cn/v1/embeddings"): - if not base_url: - base_url = "https://api.siliconflow.cn/v1/embeddings" + normalized_base_url = (base_url or "").strip() + if not normalized_base_url: + normalized_base_url = "https://api.siliconflow.cn/v1/embeddings" + if "/embeddings" not in normalized_base_url: + normalized_base_url = urljoin(f"{normalized_base_url.rstrip('/')}/", "embeddings").rstrip("/") self.headers = { "accept": "application/json", "content-type": "application/json", "authorization": f"Bearer {key}", } - self.base_url = base_url + self.base_url = normalized_base_url self.model_name = model_name def encode(self, texts: list): diff --git a/rag/llm/rerank_model.py b/rag/llm/rerank_model.py index d9a4a74059..b8fd19dacd 100644 --- a/rag/llm/rerank_model.py +++ b/rag/llm/rerank_model.py @@ -274,10 +274,13 @@ class SILICONFLOWRerank(Base): _FACTORY_NAME = "SILICONFLOW" def __init__(self, key, model_name, base_url="https://api.siliconflow.cn/v1/rerank"): - if not base_url: - base_url = "https://api.siliconflow.cn/v1/rerank" + normalized_base_url = (base_url or "").strip() + if not normalized_base_url: + normalized_base_url = "https://api.siliconflow.cn/v1/rerank" + if "/rerank" not in normalized_base_url: + normalized_base_url = urljoin(f"{normalized_base_url.rstrip('/')}/", "rerank").rstrip("/") self.model_name = model_name - self.base_url = base_url + self.base_url = normalized_base_url self.headers = { "accept": "application/json", "content-type": "application/json", diff --git a/web/src/hooks/use-llm-request.tsx b/web/src/hooks/use-llm-request.tsx index 8579c8bd45..65da65d497 100644 --- a/web/src/hooks/use-llm-request.tsx +++ b/web/src/hooks/use-llm-request.tsx @@ -271,6 +271,7 @@ export interface IApiKeySavingParams { llm_name?: string; model_type?: string; base_url?: string; + source_fid?: string; verify?: boolean; } diff --git a/web/src/locales/bg.ts b/web/src/locales/bg.ts index 6ce56f22a2..03b391cf97 100644 --- a/web/src/locales/bg.ts +++ b/web/src/locales/bg.ts @@ -1137,6 +1137,8 @@ The above is the content you need to summarize.`, 'Ако вашият API ключ е от OpenAI, просто го игнорирайте. Всеки друг междинен доставчик ще предостави този base url с API ключа.', tongyiBaseUrlTip: 'За китайски потребители не е необходимо да попълвате или използвайте https://dashscope.aliyuncs.com/compatible-mode/v1. За международни потребители използвайте https://dashscope-intl.aliyuncs.com/compatible-mode/v1', + siliconBaseUrlTip: + 'За китайски потребители не е необходимо да попълвате или използвайте https://api.siliconflow.cn/v1. За международни потребители използвайте https://api.siliconflow.com/v1', tongyiBaseUrlPlaceholder: '(Само за международни потребители, вижте съвета)', minimaxBaseUrlTip: diff --git a/web/src/locales/de.ts b/web/src/locales/de.ts index 147885ae59..508115b186 100644 --- a/web/src/locales/de.ts +++ b/web/src/locales/de.ts @@ -1177,6 +1177,8 @@ Beispiel: Virtual Hosted Style`, 'Wenn Ihr API-Schlüssel von OpenAI stammt, ignorieren Sie dies. Andere Zwischenanbieter geben diese Basis-URL mit dem API-Schlüssel an.', tongyiBaseUrlTip: 'Für chinesische Benutzer ist keine Eingabe erforderlich oder verwenden Sie https://dashscope.aliyuncs.com/compatible-mode/v1. Für internationale Benutzer verwenden Sie https://dashscope-intl.aliyuncs.com/compatible-mode/v1', + siliconBaseUrlTip: + 'Für chinesische Benutzer ist keine Eingabe erforderlich oder verwenden Sie https://api.siliconflow.cn/v1. Für internationale Benutzer verwenden Sie https://api.siliconflow.com/v1', tongyiBaseUrlPlaceholder: '(Nur für internationale Benutzer, bitte Hinweis beachten)', minimaxBaseUrlTip: diff --git a/web/src/locales/en.ts b/web/src/locales/en.ts index 357334abcf..5117713a29 100644 --- a/web/src/locales/en.ts +++ b/web/src/locales/en.ts @@ -1172,6 +1172,8 @@ Example: Virtual Hosted Style`, 'If your API key is from OpenAI, just ignore it. Any other intermediate providers will give this base url with the API key.', tongyiBaseUrlTip: 'For Chinese users, no need to fill in or use https://dashscope.aliyuncs.com/compatible-mode/v1. For international users, use https://dashscope-intl.aliyuncs.com/compatible-mode/v1', + siliconBaseUrlTip: + 'For Chinese users, no need to fill in or use https://api.siliconflow.cn/v1. For international users, use https://api.siliconflow.com/v1', tongyiBaseUrlPlaceholder: '(International users only, please see tip)', minimaxBaseUrlTip: 'International users only: use https://api.minimax.io/v1', diff --git a/web/src/locales/es.ts b/web/src/locales/es.ts index 03bbe4cf5e..816353495f 100644 --- a/web/src/locales/es.ts +++ b/web/src/locales/es.ts @@ -358,6 +358,8 @@ export default { 'Si tu clave API es de OpenAI, ignora esto. Cualquier otro proveedor intermedio proporcionará esta URL base junto con la clave API.', tongyiBaseUrlTip: 'Para usuarios chinos, no es necesario rellenar o usar https://dashscope.aliyuncs.com/compatible-mode/v1. Para usuarios internacionales, usar https://dashscope-intl.aliyuncs.com/compatible-mode/v1', + siliconBaseUrlTip: + 'Para usuarios chinos, no es necesario rellenar o usar https://api.siliconflow.cn/v1. Para usuarios internacionales, usar https://api.siliconflow.com/v1', tongyiBaseUrlPlaceholder: '(Solo para usuarios internacionales, por favor ver consejo)', minimaxBaseUrlTip: diff --git a/web/src/locales/fr.ts b/web/src/locales/fr.ts index 8e68e7d82e..ccb735c410 100644 --- a/web/src/locales/fr.ts +++ b/web/src/locales/fr.ts @@ -542,6 +542,8 @@ export default { "Si votre clé API provient d'OpenAI, ignorez ceci. Tout autre fournisseur intermédiaire fournira cette URL de base avec la clé API.", tongyiBaseUrlTip: 'Pour les utilisateurs chinois, pas besoin de remplir ou utiliser https://dashscope.aliyuncs.com/compatible-mode/v1. Pour les utilisateurs internationaux, utilisez https://dashscope-intl.aliyuncs.com/compatible-mode/v1', + siliconBaseUrlTip: + 'Pour les utilisateurs chinois, pas besoin de remplir ou utiliser https://api.siliconflow.cn/v1. Pour les utilisateurs internationaux, utilisez https://api.siliconflow.com/v1', tongyiBaseUrlPlaceholder: "(Utilisateurs internationaux uniquement, veuillez consulter l'astuce)", minimaxBaseUrlTip: diff --git a/web/src/locales/id.ts b/web/src/locales/id.ts index dc5f9a4b24..7969d85666 100644 --- a/web/src/locales/id.ts +++ b/web/src/locales/id.ts @@ -529,6 +529,8 @@ export default { 'Jika kunci API Anda berasal dari OpenAI, abaikan saja. Penyedia perantara lainnya akan memberikan base url ini dengan kunci API.', tongyiBaseUrlTip: 'Untuk pengguna Tiongkok, tidak perlu diisi atau gunakan https://dashscope.aliyuncs.com/compatible-mode/v1. Untuk pengguna internasional, gunakan https://dashscope-intl.aliyuncs.com/compatible-mode/v1', + siliconBaseUrlTip: + 'Untuk pengguna Tiongkok, tidak perlu diisi atau gunakan https://api.siliconflow.cn/v1. Untuk pengguna internasional, gunakan https://api.siliconflow.com/v1', tongyiBaseUrlPlaceholder: '(Hanya untuk pengguna internasional, silakan lihat tip)', minimaxBaseUrlTip: diff --git a/web/src/locales/it.ts b/web/src/locales/it.ts index cd003bc288..04222f4607 100644 --- a/web/src/locales/it.ts +++ b/web/src/locales/it.ts @@ -770,6 +770,8 @@ Quanto sopra è il contenuto che devi riassumere.`, baseUrl: 'URL Base', baseUrlTip: 'Se la tua chiave API è da OpenAI, ignoralo. Qualsiasi altro fornitore intermedio fornirà questo URL base con la chiave API.', + siliconBaseUrlTip: + 'For Chinese users, no need to fill in or use https://api.siliconflow.cn/v1. For international users, use https://api.siliconflow.com/v1', modify: 'Modifica', systemModelSettings: 'Imposta modelli predefiniti', chatModel: 'LLM', diff --git a/web/src/locales/ja.ts b/web/src/locales/ja.ts index 13a1a20eda..3eb93aae5e 100644 --- a/web/src/locales/ja.ts +++ b/web/src/locales/ja.ts @@ -569,6 +569,8 @@ export default { 'APIキーがOpenAIからのものであれば無視してください。他の中間プロバイダーはAPIキーと共にこのベースURLを提供します。', tongyiBaseUrlTip: '中国ユーザーの場合、記入不要または https://dashscope.aliyuncs.com/compatible-mode/v1 を使用してください。国際ユーザーは https://dashscope-intl.aliyuncs.com/compatible-mode/v1 を使用してください', + siliconBaseUrlTip: + '中国ユーザーの場合、入力不要または https://api.siliconflow.cn/v1 を使用してください。国際ユーザーは https://api.siliconflow.com/v1 を使用してください', tongyiBaseUrlPlaceholder: '(国際ユーザーのみ、ヒントをご覧ください)', minimaxBaseUrlTip: '国際ユーザーのみ:https://api.minimax.io/v1 を使用してください。', diff --git a/web/src/locales/pt-br.ts b/web/src/locales/pt-br.ts index ae313378b4..1ce96814ca 100644 --- a/web/src/locales/pt-br.ts +++ b/web/src/locales/pt-br.ts @@ -524,6 +524,8 @@ export default { 'Se sua chave da API for do OpenAI, ignore isso. Outros provedores intermediários fornecerão essa URL base com a chave da API.', tongyiBaseUrlTip: 'Para usuários chineses, não é necessário preencher ou usar https://dashscope.aliyuncs.com/compatible-mode/v1. Para usuários internacionais, use https://dashscope-intl.aliyuncs.com/compatible-mode/v1', + siliconBaseUrlTip: + 'Para usuários chineses, não é necessário preencher ou usar https://api.siliconflow.cn/v1. Para usuários internacionais, use https://api.siliconflow.com/v1', tongyiBaseUrlPlaceholder: '(Apenas para usuários internacionais, consulte a dica)', minimaxBaseUrlTip: diff --git a/web/src/locales/ru.ts b/web/src/locales/ru.ts index a9a59cefcb..60b8d8ab1c 100644 --- a/web/src/locales/ru.ts +++ b/web/src/locales/ru.ts @@ -894,6 +894,8 @@ export default { 'Если ваш API ключ от OpenAI, просто проигнорируйте это. Любые другие промежуточные провайдеры дадут этот базовый url вместе с API ключом.', tongyiBaseUrlTip: 'Для китайских пользователей не нужно заполнять или используйте https://dashscope.aliyuncs.com/compatible-mode/v1. Для международных пользователей используйте https://dashscope-intl.aliyuncs.com/compatible-mode/v1', + siliconBaseUrlTip: + 'Для китайских пользователей не нужно заполнять или используйте https://api.siliconflow.cn/v1. Для международных пользователей используйте https://api.siliconflow.com/v1', tongyiBaseUrlPlaceholder: '(Только для международных пользователей, см. подсказку)', minimaxBaseUrlTip: diff --git a/web/src/locales/vi.ts b/web/src/locales/vi.ts index 032bf236c0..ffe7312131 100644 --- a/web/src/locales/vi.ts +++ b/web/src/locales/vi.ts @@ -573,6 +573,8 @@ export default { baseUrl: 'Base-Url', baseUrlTip: 'Nếu khóa API của bạn từ OpenAI, chỉ cần bỏ qua nó. Bất kỳ nhà cung cấp trung gian nào khác sẽ cung cấp URL cơ sở này với khóa API.', + siliconBaseUrlTip: + 'For Chinese users, no need to fill in or use https://api.siliconflow.cn/v1. For international users, use https://api.siliconflow.com/v1', minimaxBaseUrlTip: 'Chỉ người dùng quốc tế: dùng https://api.minimax.io/v1.', minimaxBaseUrlPlaceholder: diff --git a/web/src/locales/zh-traditional.ts b/web/src/locales/zh-traditional.ts index ce1f4932cd..229c6bea5f 100644 --- a/web/src/locales/zh-traditional.ts +++ b/web/src/locales/zh-traditional.ts @@ -626,6 +626,8 @@ export default { '如果您的 API 密鑰來自 OpenAI,請忽略它。任何其他中間提供商都會提供帶有 API 密鑰的基本 URL。', tongyiBaseUrlTip: '中國用戶無需填寫或使用 https://dashscope.aliyuncs.com/compatible-mode/v1。國際用戶請使用 https://dashscope-intl.aliyuncs.com/compatible-mode/v1', + siliconBaseUrlTip: + '中國用戶無需填寫或使用 https://api.siliconflow.cn/v1。國際用戶請使用 https://api.siliconflow.com/v1', tongyiBaseUrlPlaceholder: '(僅國際用戶,請參閱提示)', minimaxBaseUrlTip: '僅國際用戶:使用 https://api.minimax.io/v1。', minimaxBaseUrlPlaceholder: '(僅國際用戶填寫 https://api.minimax.io/v1)', diff --git a/web/src/locales/zh.ts b/web/src/locales/zh.ts index 01e5b16716..020abcc4fa 100644 --- a/web/src/locales/zh.ts +++ b/web/src/locales/zh.ts @@ -991,6 +991,8 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于 '如果您的 API 密钥来自 OpenAI,请忽略它。 任何其他中间提供商都会提供带有 API 密钥的基本 URL。', tongyiBaseUrlTip: '对于中国用户,不需要填写或使用 https://dashscope.aliyuncs.com/compatible-mode/v1。对于国际用户,使用 https://dashscope-intl.aliyuncs.com/compatible-mode/v1。', + siliconBaseUrlTip: + '对于中国用户,不需要填写或使用 https://api.siliconflow.cn/v1。对于国际用户,使用 https://api.siliconflow.com/v1。', tongyiBaseUrlPlaceholder: '(仅国际用户需要)', minimaxBaseUrlTip: '仅国际用户:使用 https://api.minimax.io/v1。', minimaxBaseUrlPlaceholder: '(仅国际用户填写 https://api.minimax.io/v1)', diff --git a/web/src/pages/user-setting/setting-model/hooks.tsx b/web/src/pages/user-setting/setting-model/hooks.tsx index 3a5ba677b5..72bd087042 100644 --- a/web/src/pages/user-setting/setting-model/hooks.tsx +++ b/web/src/pages/user-setting/setting-model/hooks.tsx @@ -43,11 +43,20 @@ export const useSubmitApiKey = () => { if (!isVerify) { setSaveLoading(true); } - const ret = await saveApiKey({ + const payload: IApiKeySavingParams = { ...savingParams, ...postBody, verify: isVerify, - }); + }; + if (savingParams.llm_factory === LLMFactory.SILICONFLOW) { + payload.source_fid = (postBody.base_url || '') + .toLowerCase() + .includes('api.siliconflow.com') + ? 'siliconflow_intl' + : LLMFactory.SILICONFLOW; + } + + const ret = await saveApiKey(payload); if (!isVerify) { setSaveLoading(false); if (ret.code === 0) { diff --git a/web/src/pages/user-setting/setting-model/modal/api-key-modal/index.tsx b/web/src/pages/user-setting/setting-model/modal/api-key-modal/index.tsx index 4be300c024..ff7a559e26 100644 --- a/web/src/pages/user-setting/setting-model/modal/api-key-modal/index.tsx +++ b/web/src/pages/user-setting/setting-model/modal/api-key-modal/index.tsx @@ -41,6 +41,7 @@ const modelsWithBaseUrl = [ LLMFactory.AzureOpenAI, LLMFactory.TongYiQianWen, LLMFactory.MiniMax, + LLMFactory.SILICONFLOW, ]; const ApiKeyModal = ({ @@ -127,7 +128,9 @@ const ApiKeyModal = ({ ? t('minimaxBaseUrlTip') : llmFactory === LLMFactory.TongYiQianWen ? t('tongyiBaseUrlTip') - : t('baseUrlTip') + : llmFactory === LLMFactory.SILICONFLOW + ? t('siliconBaseUrlTip') + : t('baseUrlTip') } > {t('baseUrl')} @@ -140,7 +143,9 @@ const ApiKeyModal = ({ ? t('tongyiBaseUrlPlaceholder') : llmFactory === LLMFactory.MiniMax ? t('minimaxBaseUrlPlaceholder') - : 'https://api.openai.com/v1' + : llmFactory === LLMFactory.SILICONFLOW + ? 'https://api.siliconflow.cn/v1' + : 'https://api.openai.com/v1' } onKeyDown={handleKeyDown} className="w-full"