diff --git a/core/config/types.ts b/core/config/types.ts index 6c8362e4af..077c076991 100644 --- a/core/config/types.ts +++ b/core/config/types.ts @@ -604,7 +604,8 @@ declare global { | "openrouter" | "sambanova" | "nvidia" - | "nebius"; + | "nebius" + | "siliconflow"; export type ModelName = | "AUTODETECT" diff --git a/core/config/validation.ts b/core/config/validation.ts index 062c0eaedd..e10b3f5232 100644 --- a/core/config/validation.ts +++ b/core/config/validation.ts @@ -63,7 +63,8 @@ export function validateConfig(config: SerializedContinueConfig) { if ( nonAutocompleteModels.some((m) => modelName.includes(m)) && !modelName.includes("deepseek") && - !modelName.includes("codestral") + !modelName.includes("codestral") && + !modelName.toLowerCase().includes("coder") ) { errors.push({ fatal: false, diff --git a/core/control-plane/schema.ts b/core/control-plane/schema.ts index e6987f1fed..4aae9f3ccb 100644 --- a/core/control-plane/schema.ts +++ b/core/control-plane/schema.ts @@ -17,6 +17,7 @@ const modelDescriptionSchema = z.object({ "cloudflare", "azure", "nebius", + "siliconflow", ]), model: z.string(), apiKey: z.string().optional(), @@ -84,6 +85,7 @@ const embeddingsProviderSchema = z.object({ "free-trial", "gemini", "nebius", + "siliconflow", ]), apiBase: z.string().optional(), apiKey: z.string().optional(), diff --git a/core/index.d.ts b/core/index.d.ts index 1f072112e1..efb7a18e94 100644 --- a/core/index.d.ts +++ b/core/index.d.ts @@ -699,7 +699,8 @@ type ModelProvider = | "vertexai" | "nebius" | "xAI" - | "moonshot"; + | "moonshot" + | "siliconflow"; export type ModelName = | "AUTODETECT" @@ -911,7 +912,8 @@ export type EmbeddingsProviderName = | "mistral" | "nebius" | "vertexai" - | "watsonx"; + | "watsonx" + | "siliconflow"; export interface EmbedOptions { apiBase?: string; diff --git a/core/indexing/embeddings/SiliconFlowEmbeddingsProvider.ts b/core/indexing/embeddings/SiliconFlowEmbeddingsProvider.ts new file mode 100644 index 0000000000..bc463b0470 --- /dev/null +++ b/core/indexing/embeddings/SiliconFlowEmbeddingsProvider.ts @@ -0,0 +1,14 @@ +import { EmbeddingsProviderName, EmbedOptions } from "../.."; + +import OpenAIEmbeddingsProvider from "./OpenAIEmbeddingsProvider"; + +class SiliconFlowEmbeddingsProvider extends OpenAIEmbeddingsProvider { + static providerName: EmbeddingsProviderName = "siliconflow"; + + static defaultOptions: Partial | undefined = { + apiBase: "https://api.siliconflow.cn/v1/", + model: "BAAI/bge-m3", + }; +} + +export default SiliconFlowEmbeddingsProvider; diff --git a/core/indexing/embeddings/index.ts b/core/indexing/embeddings/index.ts index 90e450361c..3e895a39e6 100644 --- a/core/indexing/embeddings/index.ts +++ b/core/indexing/embeddings/index.ts @@ -15,6 +15,7 @@ import NvidiaEmbeddingsProvider from "./NvidiaEmbeddingsProvider.js"; import OllamaEmbeddingsProvider from "./OllamaEmbeddingsProvider.js"; import OpenAIEmbeddingsProvider from "./OpenAIEmbeddingsProvider.js"; import SageMakerEmbeddingsProvider from "./SageMakerEmbeddingsProvider.js"; +import SiliconFlowEmbeddingsProvider from "./SiliconFlowEmbeddingsProvider.js"; import TransformersJsEmbeddingsProvider from "./TransformersJsEmbeddingsProvider.js"; import VertexEmbeddingsProvider from "./VertexEmbeddingsProvider.js"; import VoyageEmbeddingsProvider from "./VoyageEmbeddingsProvider.js"; @@ -45,5 +46,6 @@ export const allEmbeddingsProviders: Record< nebius: NebiusEmbeddingsProvider, vertexai: VertexEmbeddingsProvider, watsonx: WatsonxEmbeddingsProvider, - lmstudio: LMStudioEmbeddingsProvider + lmstudio: LMStudioEmbeddingsProvider, + siliconflow: SiliconFlowEmbeddingsProvider, }; diff --git a/core/llm/llms/OpenAI.ts b/core/llm/llms/OpenAI.ts index e8b989f3a9..4f929b5067 100644 --- a/core/llm/llms/OpenAI.ts +++ b/core/llm/llms/OpenAI.ts @@ -333,4 +333,4 @@ class OpenAI extends BaseLLM { } } -export default OpenAI; +export default OpenAI; \ No newline at end of file diff --git a/core/llm/llms/SiliconFlow.ts b/core/llm/llms/SiliconFlow.ts new file mode 100644 index 0000000000..86804cb45d --- /dev/null +++ b/core/llm/llms/SiliconFlow.ts @@ -0,0 +1,58 @@ +import { CompletionOptions, LLMOptions, ModelProvider } from "../../index.js"; +import { streamSse } from "../stream.js"; +import { osModelsEditPrompt } from "../templates/edit.js"; + +import OpenAI from "./OpenAI.js"; + +class SiliconFlow extends OpenAI { + static providerName: ModelProvider = "siliconflow"; + static defaultOptions: Partial = { + apiBase: "https://api.siliconflow.cn/v1/", + model: "Qwen/Qwen2.5-Coder-32B-Instruct", + promptTemplates: { + edit: osModelsEditPrompt, + }, + useLegacyCompletionsEndpoint: false, + }; + maxStopWords: number | undefined = 16; + + supportsFim(): boolean { + return true; + } + + async *_streamFim( + prefix: string, + suffix: string, + signal: AbortSignal, + options: CompletionOptions, + ): AsyncGenerator { + const endpoint = new URL("completions", this.apiBase); + const resp = await this.fetch(endpoint, { + method: "POST", + body: JSON.stringify({ + model: options.model, + prompt: prefix, + suffix, + max_tokens: options.maxTokens, + temperature: options.temperature, + top_p: options.topP, + frequency_penalty: options.frequencyPenalty, + presence_penalty: options.presencePenalty, + stop: options.stop, + stream: true, + }), + headers: { + "Content-Type": "application/json", + Accept: "application/json", + Authorization: `Bearer ${this.apiKey}`, + }, + signal + }); + for await (const chunk of streamSse(resp)) { + yield chunk.choices[0].text; + } + } + +} + +export default SiliconFlow; diff --git a/core/llm/llms/index.ts b/core/llm/llms/index.ts index 121f0f46d5..0297b7868a 100644 --- a/core/llm/llms/index.ts +++ b/core/llm/llms/index.ts @@ -48,6 +48,7 @@ import VertexAI from "./VertexAI"; import Vllm from "./Vllm"; import WatsonX from "./WatsonX"; import xAI from "./xAI"; +import SiliconFlow from "./SiliconFlow"; const LLMs = [ Anthropic, @@ -90,6 +91,7 @@ const LLMs = [ Nebius, VertexAI, xAI, + SiliconFlow, ]; export async function llmFromDescription( diff --git a/docs/docs/customize/model-providers/more/siliconflow.md b/docs/docs/customize/model-providers/more/siliconflow.md new file mode 100644 index 0000000000..c27fbbdaf3 --- /dev/null +++ b/docs/docs/customize/model-providers/more/siliconflow.md @@ -0,0 +1,49 @@ +--- +title: SiliconFlow +--- + +:::info + +You can get an API key from the [Silicon Cloud](https://cloud.siliconflow.cn/account/ak). + +::: + +## Chat model + +We recommend configuring **Qwen/Qwen2.5-Coder-32B-Instruct** as your chat model. + +```json title="config.json" +{ + "models": [ + { + "title": "Qwen", + "provider": "siliconflow", + "model": "Qwen/Qwen2.5-Coder-32B-Instruct", + "apiKey": "[API_KEY]" + } + ] +} +``` + +## Autocomplete model + +We recommend configuring **Qwen/Qwen2.5-Coder-7B-Instruct** as your autocomplete model. + +```json title="config.json" +{ + "tabAutocompleteModel": { + "title": "Qwen", + "provider": "siliconflow", + "model": "Qwen/Qwen2.5-Coder-7B-Instruct", + "apiKey": "[API_KEY]" + } +} +``` + +## Embeddings model + +SiliconFlow provide some embeddings models, [Click here](https://siliconflow.cn/models) to see a list of embeddings models. + +## Reranking model + +SiliconFlow provide some reranking models, [Click here](https://siliconflow.cn/models) to see a list of reranking models. diff --git a/docs/i18n/zh-CN/docusaurus-plugin-content-docs/current/customize/model-providers/more/siliconflow.md b/docs/i18n/zh-CN/docusaurus-plugin-content-docs/current/customize/model-providers/more/siliconflow.md new file mode 100644 index 0000000000..b871018327 --- /dev/null +++ b/docs/i18n/zh-CN/docusaurus-plugin-content-docs/current/customize/model-providers/more/siliconflow.md @@ -0,0 +1,51 @@ +--- +title: 硅基流动 +--- + +:::info + +你可以从 [Silicon Cloud](https://cloud.siliconflow.cn/account/ak) 获取 API key 。 + +::: + +## 聊天模型 + +我们推荐配置 **Qwen/Qwen2.5-Coder-32B-Instruct** 作为你的聊天模型。 + +```json title="config.json" +{ + "models": [ + { + "title": "Qwen", + "provider": "siliconflow", + "model": "Qwen/Qwen2.5-Coder-32B-Instruct", + "apiKey": "[API_KEY]" + } + ] +} +``` + +## 自动补全模型 + +我们推荐配置 **Qwen/Qwen2.5-Coder-7B-Instruct** 作为你的自动补全模型。 + +```json title="config.json" +{ + "tabAutocompleteModel": { + "title": "Qwen", + "provider": "siliconflow", + "model": "Qwen/Qwen2.5-Coder-7B-Instruct", + "apiKey": "[API_KEY]" + } +} +``` + +## 嵌入模型 + +SiliconFlow 提供了一些嵌入模型,[点击这里](https://siliconflow.cn/models) 查看所有的嵌入模型. + +## 重排序模型 + +SiliconFlow 提供了一些重排序模型,[点击这里](https://siliconflow.cn/models) 查看所有的重排序模型. + +[Click here](https://siliconflow.cn/models) to see a list of reranking models. diff --git a/extensions/vscode/config_schema.json b/extensions/vscode/config_schema.json index 3a274c8b02..6829258384 100644 --- a/extensions/vscode/config_schema.json +++ b/extensions/vscode/config_schema.json @@ -206,7 +206,8 @@ "vertexai", "xAI", "kindo", - "moonshot" + "moonshot", + "siliconflow" ], "markdownEnumDescriptions": [ "### OpenAI\nUse gpt-4, gpt-3.5-turbo, or any other OpenAI model. See [here](https://openai.com/product#made-for-developers) to obtain an API key.\n\n> [Reference](https://docs.continue.dev/reference/Model%20Providers/openai)", @@ -244,7 +245,8 @@ "### Ask Sage\nAsk Sage is an agnostic hosted service that provides language models. To get started with Ask Sage:\n1. Obtain an API key from your account. For more information, visit [Ask Sage](https://docs.asksage.ai/).\n2. Paste the API key below.\n3. Select a model preset.\n> [Reference](https://docs.asksage.ai/)", "### xAI offers a world class developer tool set to build scalable applications powered by Grok. To get started, obtain an API key from [the x Console](https://console.x.ai/), and see the [docs](https://docs.x.ai/docs/)", "### Secure AI management software that helps enterprises adopt and manage AI across their workforce. To get started, obtain an API key from [the Kindo console](https://app.kindo.ai/settings/api), and see the [website](https://app.kindo.ai//)", - "### Moonshot\nTo get started with Moonshot AI, obtain your API key from [Moonshot AI](https://platform.moonshot.cn/). Moonshot AI provides high-quality large language models with competitive pricing.\n> [Reference](https://platform.moonshot.cn/docs/api)" + "### Moonshot\nTo get started with Moonshot AI, obtain your API key from [Moonshot AI](https://platform.moonshot.cn/). Moonshot AI provides high-quality large language models with competitive pricing.\n> [Reference](https://platform.moonshot.cn/docs/api)", + "### SiliconFlow\nTo get started with SiliconFlow, obtain your API key from [SiliconCloud](https://cloud.siliconflow.cn/account/ak). SiliconCloud provides cost-effective GenAI services based on excellent open source basic models.\n> [Models](https://siliconflow.cn/zh-cn/models)" ], "type": "string" }, @@ -1235,6 +1237,27 @@ } } }, + { + "if": { + "properties": { + "provider": { + "enum": ["siliconflow"] + } + }, + "required": ["provider"] + }, + "then": { + "properties": { + "model": { + "enum": [ + "Qwen/Qwen2.5-Coder-32B-Instruct", + "Qwen/Qwen2.5-Coder-7B-Instruct", + "Pro/Qwen/Qwen2.5-Coder-7B-Instruct" + ] + } + } + } + }, { "if": { "properties": { @@ -2500,7 +2523,8 @@ "deepinfra", "mistral", "watsonx", - "lmstudio" + "lmstudio", + "siliconflow" ] }, "model": { @@ -2548,7 +2572,7 @@ "if": { "properties": { "provider": { - "enum": ["cohere", "voyage", "nvidia", "gemini"] + "enum": ["cohere", "voyage", "nvidia", "gemini", "siliconflow"] } }, "required": ["provider"] diff --git a/gui/src/components/OnboardingCard/tabs/OnboardingLocalTab.tsx b/gui/src/components/OnboardingCard/tabs/OnboardingLocalTab.tsx index e937070c94..ac0273ab9c 100644 --- a/gui/src/components/OnboardingCard/tabs/OnboardingLocalTab.tsx +++ b/gui/src/components/OnboardingCard/tabs/OnboardingLocalTab.tsx @@ -24,19 +24,19 @@ function OnboardingLocalTab() { hasPassedFTL() ? "LocalAfterFreeTrial" : "Local", ); const [hasLoadedChatModel, setHasLoadedChatModel] = useState(false); - const [downloadedOllamaModels, setDownloadedOllamaModels] = useState< - string[] - >([]); + const [downloadedOllamaModels, setDownloadedOllamaModels] = useState([]); const [isOllamaConnected, setIsOllamaConnected] = useState(false); - const hasDownloadedChatModel = downloadedOllamaModels.some((ollamaModel) => - ollamaModel.startsWith(LOCAL_ONBOARDING_CHAT_MODEL), - ); + const hasDownloadedChatModel = Array.isArray(downloadedOllamaModels) + ? downloadedOllamaModels.some((ollamaModel) => + ollamaModel.startsWith(LOCAL_ONBOARDING_CHAT_MODEL)) + : false; - const hasDownloadedAutocompleteModel = downloadedOllamaModels.some( - (ollamaModel) => ollamaModel.startsWith(LOCAL_ONBOARDING_CHAT_MODEL), - ); + const hasDownloadedAutocompleteModel = Array.isArray(downloadedOllamaModels) + ? downloadedOllamaModels.some((ollamaModel) => + ollamaModel.startsWith(LOCAL_ONBOARDING_CHAT_MODEL)) + : false; /** * The first time we detect that a chat model has been loaded, diff --git a/gui/src/pages/AddNewModel/configs/models.ts b/gui/src/pages/AddNewModel/configs/models.ts index 5e55c5c64c..e9eecaf495 100644 --- a/gui/src/pages/AddNewModel/configs/models.ts +++ b/gui/src/pages/AddNewModel/configs/models.ts @@ -1175,6 +1175,45 @@ export const models: { [key: string]: ModelPackage } = { }, isOpenSource: true, }, + Qwen25Coder_7b: { + title: "Qwen 2.5 Coder 7b", + description: + "Qwen 2.5 is an auto-regressive language model that uses an optimized transformer architecture.", + params: { + title: "Qwen 2.5 Coder 7b", + model: "Qwen/Qwen2.5-Coder-7B-Instruct", + contextLength: 32_000, + }, + icon: "qwen.png", + providerOptions: ["siliconflow"], + isOpenSource: true, + }, + Qwen25Coder_7b_pro: { + title: "Qwen 2.5 Coder 7b pro", + description: + "Qwen 2.5 is an auto-regressive language model that uses an optimized transformer architecture.", + params: { + title: "Qwen 2.5 Coder 7b pro", + model: "Pro/Qwen/Qwen2.5-Coder-7B-Instruct", + contextLength: 32_000, + }, + icon: "qwen.png", + providerOptions: ["siliconflow"], + isOpenSource: true, + }, + Qwen25Coder_32b: { + title: "Qwen 2.5 Coder 32b", + description: + "Qwen 2.5 is an auto-regressive language model that uses an optimized transformer architecture.", + params: { + title: "Qwen 2.5 Coder 32b", + model: "Qwen/Qwen2.5-Coder-32B-Instruct", + contextLength: 128_000, + }, + icon: "qwen.png", + providerOptions: ["siliconflow"], + isOpenSource: true, + }, AUTODETECT: { title: "Autodetect", description: diff --git a/gui/src/pages/AddNewModel/configs/providers.ts b/gui/src/pages/AddNewModel/configs/providers.ts index 3100f1ddc7..cc668c0c26 100644 --- a/gui/src/pages/AddNewModel/configs/providers.ts +++ b/gui/src/pages/AddNewModel/configs/providers.ts @@ -125,9 +125,7 @@ export const providers: Partial> = { tags: [ModelProviderTags.RequiresApiKey], refPage: "moonshot", apiKeyUrl: "https://docs.moonshot.cn/docs/getting-started", - packages: [ - models.moonshotChat, - ], + packages: [models.moonshotChat], collectInputFor: [ { inputType: "text", @@ -785,4 +783,28 @@ To get started, [register](https://dataplatform.cloud.ibm.com/registration/stepo ], apiKeyUrl: "https://studio.nebius.ai/settings/api-keys", }, + siliconflow: { + title: "SiliconFlow", + provider: "siliconflow", + icon: "siliconflow.png", + description: "SiliconFlow provides cheap open-source models.", + longDescription: + "To get started with SiliconFlow, obtain an API key from their website [here](https://cloud.siliconflow.cn/account/ak).", + tags: [ModelProviderTags.RequiresApiKey, ModelProviderTags.OpenSource], + collectInputFor: [ + { + inputType: "text", + key: "apiKey", + label: "API Key", + placeholder: "Enter your SiliconFlow API key", + required: true, + }, + ], + packages: [ + models.Qwen25Coder_7b, + models.Qwen25Coder_7b_pro, + models.Qwen25Coder_32b, + ], + apiKeyUrl: "https://cloud.siliconflow.cn/account/ak", + }, };