diff --git a/src/renderer/packages/model-setting-utils/huaweicloud-maas-setting-util.ts b/src/renderer/packages/model-setting-utils/huaweicloud-maas-setting-util.ts new file mode 100644 index 000000000..f202c5b93 --- /dev/null +++ b/src/renderer/packages/model-setting-utils/huaweicloud-maas-setting-util.ts @@ -0,0 +1,62 @@ +import { ModelProvider, ModelProviderEnum, ProviderSettings, SessionType } from 'src/shared/types' +import { ModelSettingUtil } from './interface' +import HuaweiCloudMaaS from '../models/huaweicloud-maas' +import BaseConfig from './base-config' + +export default class HuaweiCloudMAASSettingUtil extends BaseConfig implements ModelSettingUtil { + public provider: ModelProvider = ModelProviderEnum.HuaweiCloudMaaS + + async getCurrentModelDisplayName( + model: string, + sessionType: SessionType, + providerSettings?: ProviderSettings + ): Promise { + return `HuaweiCloudMaaS API (${providerSettings?.models?.find((m) => m.modelId === model)?.nickname || model})` + } + + public getLocalOptionGroups() { + // HuaweiCloudMaaS支持的所有模型 + + const deepseekModels = [ + 'deepseek-r1-250528', + 'DeepSeek-V3', + 'DeepSeek-R1' + ] + + const qwenModels = [ + 'qwen3-235b-a22b', + 'qwen3-32b' + ] + + return [ + { + group_name: 'DeepSeek 系列', + options: deepseekModels.map((value) => ({ + label: value, + value: value, + })), + collapsable: true, + }, + { + group_name: '千问 系列', + options: qwenModels.map((value) => ({ + label: value, + value: value, + })), + collapsable: true, + }, + ] + } + + protected async listProviderModels() { + return [] + } + + isCurrentModelSupportImageInput(model: string): boolean { + return HuaweiCloudMaaS.helpers.isModelSupportVision(model) + } + + isCurrentModelSupportToolUse(model: string): boolean { + return HuaweiCloudMaaS.helpers.isModelSupportToolUse(model) + } +} \ No newline at end of file diff --git a/src/renderer/packages/model-setting-utils/index.ts b/src/renderer/packages/model-setting-utils/index.ts index 0d943f573..00e807a15 100644 --- a/src/renderer/packages/model-setting-utils/index.ts +++ b/src/renderer/packages/model-setting-utils/index.ts @@ -16,6 +16,7 @@ import PerplexitySettingUtil from './perplexity-setting-util' import SiliconFlowSettingUtil from './siliconflow-setting-util' import VolcEngineSettingUtil from './volcengine-setting-util' import XAISettingUtil from './xai-setting-util' +import HuaweiCloudMAASSettingUtil from './huaweicloud-maas-setting-util' export function getModelSettingUtil(aiProvider: ModelProvider): ModelSettingUtil { const hash: Record ModelSettingUtil> = { @@ -33,6 +34,7 @@ export function getModelSettingUtil(aiProvider: ModelProvider): ModelSettingUtil [ModelProviderEnum.LMStudio]: LMStudioSettingUtil, [ModelProviderEnum.Perplexity]: PerplexitySettingUtil, [ModelProviderEnum.XAI]: XAISettingUtil, + [ModelProviderEnum.HuaweiCloudMaaS]: HuaweiCloudMAASSettingUtil, [ModelProviderEnum.Custom]: CustomModelSettingUtil, } const Class = hash[aiProvider] || CustomModelSettingUtil diff --git a/src/renderer/packages/models/huaweicloud-maas.ts b/src/renderer/packages/models/huaweicloud-maas.ts new file mode 100644 index 000000000..93df5f5be --- /dev/null +++ b/src/renderer/packages/models/huaweicloud-maas.ts @@ -0,0 +1,95 @@ +import { fetchWithProxy } from '@/utils/request' +import { createOpenAICompatible } from '@ai-sdk/openai-compatible' +import { extractReasoningMiddleware, wrapLanguageModel } from 'ai' +import AbstractAISDKModel from './abstract-ai-sdk' +import { ProviderModelInfo } from 'src/shared/types' +import { fetchRemoteModels } from './openai-compatible' + +const helpers = { + isModelSupportVision: (model: string) => { + // HuaweiCloudMaaS支持视觉的模型 + return false + }, + isModelSupportToolUse: (model: string) => { + // HuaweiCloudMaaS支持工具使用的模型(除了纯图像生成和推理专用模型) + const nonToolModels = [ + 'qwen3-235b-a22b', + 'qwen3-32b' + ] + return !nonToolModels.some(nonToolModel => model.includes(nonToolModel)) + }, +} + +interface Options { + apiKey: string + apiHost: string + model: ProviderModelInfo + temperature?: number + topP?: number + useProxy?: boolean +} + +export default class HuaweiCloudMaaS extends AbstractAISDKModel { + public name = 'HuaweiCloudMaaS' + public static helpers = helpers + public options: Options + + constructor(options: Options) { + super(options) + this.options = { + ...options, + apiHost: options.apiHost || 'https://ai.huaweicloud.com/v1', + } + } + + public isSupportToolUse() { + return helpers.isModelSupportToolUse(this.options.model.modelId) + } + + private getProvider() { + return createOpenAICompatible({ + name: 'HuaweiCloudMaaS', + apiKey: this.options.apiKey, + baseURL: this.options.apiHost, + fetch: this.options.useProxy ? fetchWithProxy : undefined, + }) + } + + protected getChatModel() { + const provider = this.getProvider() + return wrapLanguageModel({ + model: provider.languageModel(this.options.model.modelId), + middleware: extractReasoningMiddleware({ tagName: 'think' }), + }) + } + + protected getImageModel() { + const provider = this.getProvider() + return provider.imageModel('dall-e-3') + } + + protected getCallSettings() { + return { + temperature: this.options.temperature, + topP: this.options.topP, + } + } + + public async listModels(): Promise { + return fetchRemoteModels({ + apiHost: this.options.apiHost, + apiKey: this.options.apiKey, + useProxy: this.options.useProxy, + }).catch((err) => { + console.error('HuaweiCloudMaaS models fetch error:', err) + // 返回HuaweiCloudMaaS支持的常见模型作为备选 + return [ + 'deepseek-r1-250528', + 'DeepSeek-V3', + 'DeepSeek-R1', + 'qwen3-235b-a22b', + 'qwen3-32b' + ] + }) + } +} \ No newline at end of file diff --git a/src/renderer/packages/models/index.ts b/src/renderer/packages/models/index.ts index b05f38984..fd590b0a9 100644 --- a/src/renderer/packages/models/index.ts +++ b/src/renderer/packages/models/index.ts @@ -16,6 +16,7 @@ import SiliconFlow from './siliconflow' import type { ModelInterface } from './types' import VolcEngine from './volcengine' import XAI from './xai' +import HuaweiCloudMaaS from './huaweicloud-maas' export function getModel(setting: Settings, config: Config): ModelInterface { const provider = setting.provider @@ -126,6 +127,15 @@ export function getModel(setting: Settings, config: Config): ModelInterface { topP: setting.topP, }) + case ModelProviderEnum.HuaweiCloudMaaS: + return new HuaweiCloudMaaS({ + apiKey: providerSetting.apiKey || '', + apiHost: formattedApiHost, + model, + temperature: setting.temperature, + topP: setting.topP, + }) + case ModelProviderEnum.SiliconFlow: return new SiliconFlow({ siliconCloudKey: providerSetting.apiKey || '', diff --git a/src/renderer/static/icons/providers/huaweicloud-maas.png b/src/renderer/static/icons/providers/huaweicloud-maas.png new file mode 100644 index 000000000..377156de0 Binary files /dev/null and b/src/renderer/static/icons/providers/huaweicloud-maas.png differ diff --git a/src/shared/defaults.ts b/src/shared/defaults.ts index cdef74d28..95b106a1d 100644 --- a/src/shared/defaults.ts +++ b/src/shared/defaults.ts @@ -592,4 +592,39 @@ export const SystemProviders: ProviderBaseInfo[] = [ ], }, }, + { + id: ModelProviderEnum.HuaweiCloudMaaS, + name: 'HuaweiCloudMaaS', + type: ModelProviderType.OpenAI, + defaultSettings: { + apiHost: 'https://api.modelarts-maas.com/v1/', + models: [ + { + modelId: 'deepseek-r1-250528', + capabilities: ['reasoning', 'tool_use'], + contextWindow: 64_000, + }, + { + modelId: 'DeepSeek-V3', + capabilities: ['tool_use'], + contextWindow: 64_000, + }, + { + modelId: 'DeepSeek-R1', + capabilities: ['reasoning', 'tool_use'], + contextWindow: 64_000, + }, + { + modelId: 'qwen3-235b-a22b', + capabilities: ['reasoning'], + contextWindow: 32_000, + }, + { + modelId: 'qwen3-32b', + capabilities: ['reasoning'], + contextWindow: 32_000, + } + ], + }, + }, ] diff --git a/src/shared/types.ts b/src/shared/types.ts index 83e7756ab..88c0130ba 100644 --- a/src/shared/types.ts +++ b/src/shared/types.ts @@ -230,6 +230,7 @@ export enum ModelProviderEnum { Perplexity = 'perplexity', XAI = 'xAI', Custom = 'custom', + HuaweiCloudMaaS = 'huaweicloud-maas', } export type ModelProvider = ModelProviderEnum | string