mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-31 16:49:07 +08:00
feat: implement isNewApiProvider utility for provider identification
- Added isNewApiProvider function to streamline checks for 'new-api' and 'cherryin' providers. - Updated ApiClientFactory, providerConfig, and various components to utilize isNewApiProvider for improved readability and maintainability. - Refactored conditional checks across multiple files to replace direct string comparisons with the new utility function.
This commit is contained in:
parent
adacb8c638
commit
287c96ea2e
@ -1,4 +1,5 @@
|
||||
import { loggerService } from '@logger'
|
||||
import { isNewApiProvider } from '@renderer/config/providers'
|
||||
import { Provider } from '@renderer/types'
|
||||
|
||||
import { AihubmixAPIClient } from './aihubmix/AihubmixAPIClient'
|
||||
@ -45,7 +46,7 @@ export class ApiClientFactory {
|
||||
return instance
|
||||
}
|
||||
|
||||
if (provider.id === 'new-api') {
|
||||
if (isNewApiProvider(provider)) {
|
||||
logger.debug(`Creating NewAPIClient for provider: ${provider.id}`)
|
||||
instance = new NewAPIClient(provider) as BaseApiClient
|
||||
return instance
|
||||
|
||||
@ -67,7 +67,9 @@ vi.mock('@renderer/config/models', () => ({
|
||||
silicon: [],
|
||||
defaultModel: []
|
||||
},
|
||||
isOpenAIModel: vi.fn(() => false)
|
||||
isOpenAIModel: vi.fn(() => false),
|
||||
glm45FlashModel: {},
|
||||
qwen38bModel: {}
|
||||
}))
|
||||
|
||||
describe('ApiClientFactory', () => {
|
||||
|
||||
@ -35,18 +35,8 @@ vi.mock('@renderer/config/models', () => ({
|
||||
findTokenLimit: vi.fn().mockReturnValue(4096),
|
||||
isFunctionCallingModel: vi.fn().mockReturnValue(false),
|
||||
DEFAULT_MAX_TOKENS: 4096,
|
||||
qwen38bModel: {
|
||||
id: 'Qwen/Qwen3-8B',
|
||||
name: 'Qwen3-8B',
|
||||
provider: 'cherryai',
|
||||
group: 'Qwen'
|
||||
},
|
||||
glm45FlashModel: {
|
||||
id: 'glm-4.5-flash',
|
||||
name: 'GLM-4.5-Flash',
|
||||
provider: 'cherryai',
|
||||
group: 'GLM-4.5'
|
||||
}
|
||||
qwen38bModel: {},
|
||||
glm45FlashModel: {}
|
||||
}))
|
||||
|
||||
vi.mock('@renderer/services/AssistantService', () => ({
|
||||
|
||||
@ -6,6 +6,7 @@ import {
|
||||
type ProviderSettingsMap
|
||||
} from '@cherrystudio/ai-core/provider'
|
||||
import { isOpenAIChatCompletionOnlyModel } from '@renderer/config/models'
|
||||
import { isNewApiProvider } from '@renderer/config/providers'
|
||||
import {
|
||||
getAwsBedrockAccessKeyId,
|
||||
getAwsBedrockRegion,
|
||||
@ -65,7 +66,7 @@ function handleSpecialProviders(model: Model, provider: Provider): Provider {
|
||||
if (provider.id === 'aihubmix') {
|
||||
return aihubmixProviderCreator(model, provider)
|
||||
}
|
||||
if (provider.id === 'new-api') {
|
||||
if (isNewApiProvider(provider)) {
|
||||
return newApiResolverCreator(model, provider)
|
||||
}
|
||||
if (provider.id === 'vertexai') {
|
||||
|
||||
@ -138,16 +138,6 @@ export const SYSTEM_PROVIDERS_CONFIG: Record<SystemProviderId, SystemProvider> =
|
||||
isSystem: true,
|
||||
enabled: false
|
||||
},
|
||||
ppio: {
|
||||
id: 'ppio',
|
||||
name: 'PPIO',
|
||||
type: 'openai',
|
||||
apiKey: '',
|
||||
apiHost: 'https://api.ppinfra.com/v3/openai/',
|
||||
models: SYSTEM_MODELS.ppio,
|
||||
isSystem: true,
|
||||
enabled: false
|
||||
},
|
||||
alayanew: {
|
||||
id: 'alayanew',
|
||||
name: 'AlayaNew',
|
||||
@ -158,16 +148,6 @@ export const SYSTEM_PROVIDERS_CONFIG: Record<SystemProviderId, SystemProvider> =
|
||||
isSystem: true,
|
||||
enabled: false
|
||||
},
|
||||
qiniu: {
|
||||
id: 'qiniu',
|
||||
name: 'Qiniu',
|
||||
type: 'openai',
|
||||
apiKey: '',
|
||||
apiHost: 'https://api.qnaigc.com',
|
||||
models: SYSTEM_MODELS.qiniu,
|
||||
isSystem: true,
|
||||
enabled: false
|
||||
},
|
||||
dmxapi: {
|
||||
id: 'dmxapi',
|
||||
name: 'DMXAPI',
|
||||
@ -178,6 +158,16 @@ export const SYSTEM_PROVIDERS_CONFIG: Record<SystemProviderId, SystemProvider> =
|
||||
isSystem: true,
|
||||
enabled: false
|
||||
},
|
||||
aionly: {
|
||||
id: 'aionly',
|
||||
name: 'AIOnly',
|
||||
type: 'openai',
|
||||
apiKey: '',
|
||||
apiHost: 'https://api.aiionly.com',
|
||||
models: SYSTEM_MODELS.aionly,
|
||||
isSystem: true,
|
||||
enabled: false
|
||||
},
|
||||
burncloud: {
|
||||
id: 'burncloud',
|
||||
name: 'BurnCloud',
|
||||
@ -238,6 +228,26 @@ export const SYSTEM_PROVIDERS_CONFIG: Record<SystemProviderId, SystemProvider> =
|
||||
isSystem: true,
|
||||
enabled: false
|
||||
},
|
||||
ppio: {
|
||||
id: 'ppio',
|
||||
name: 'PPIO',
|
||||
type: 'openai',
|
||||
apiKey: '',
|
||||
apiHost: 'https://api.ppinfra.com/v3/openai/',
|
||||
models: SYSTEM_MODELS.ppio,
|
||||
isSystem: true,
|
||||
enabled: false
|
||||
},
|
||||
qiniu: {
|
||||
id: 'qiniu',
|
||||
name: 'Qiniu',
|
||||
type: 'openai',
|
||||
apiKey: '',
|
||||
apiHost: 'https://api.qnaigc.com',
|
||||
models: SYSTEM_MODELS.qiniu,
|
||||
isSystem: true,
|
||||
enabled: false
|
||||
},
|
||||
openrouter: {
|
||||
id: 'openrouter',
|
||||
name: 'OpenRouter',
|
||||
@ -612,16 +622,6 @@ export const SYSTEM_PROVIDERS_CONFIG: Record<SystemProviderId, SystemProvider> =
|
||||
models: SYSTEM_MODELS['poe'],
|
||||
isSystem: true,
|
||||
enabled: false
|
||||
},
|
||||
aionly: {
|
||||
id: 'aionly',
|
||||
name: 'AIOnly',
|
||||
type: 'openai',
|
||||
apiKey: '',
|
||||
apiHost: 'https://api.aiionly.com',
|
||||
models: SYSTEM_MODELS.aionly,
|
||||
isSystem: true,
|
||||
enabled: false
|
||||
}
|
||||
} as const
|
||||
|
||||
@ -1375,3 +1375,7 @@ const SUPPORT_GEMINI_NATIVE_WEB_SEARCH_PROVIDERS = ['gemini', 'vertexai'] as con
|
||||
export const isGeminiWebSearchProvider = (provider: Provider) => {
|
||||
return SUPPORT_GEMINI_NATIVE_WEB_SEARCH_PROVIDERS.some((id) => id === provider.id)
|
||||
}
|
||||
|
||||
export const isNewApiProvider = (provider: Provider) => {
|
||||
return ['new-api', 'cherryin'].includes(provider.id)
|
||||
}
|
||||
|
||||
@ -17,6 +17,7 @@ import {
|
||||
isVisionModel,
|
||||
isWebSearchModel
|
||||
} from '@renderer/config/models'
|
||||
import { isNewApiProvider } from '@renderer/config/providers'
|
||||
import { useDynamicLabelWidth } from '@renderer/hooks/useDynamicLabelWidth'
|
||||
import { Model, ModelCapability, ModelType, Provider } from '@renderer/types'
|
||||
import { getDefaultGroupName, getDifference, getUnion, uniqueObjectArray } from '@renderer/utils'
|
||||
@ -78,7 +79,7 @@ const ModelEditContent: FC<ModelEditContentProps & ModalProps> = ({ provider, mo
|
||||
id: formValues.id || model.id,
|
||||
name: formValues.name || model.name,
|
||||
group: formValues.group || model.group,
|
||||
endpoint_type: provider.id === 'new-api' ? formValues.endpointType : model.endpoint_type,
|
||||
endpoint_type: isNewApiProvider(provider) ? formValues.endpointType : model.endpoint_type,
|
||||
capabilities: overrides?.capabilities ?? modelCapabilities,
|
||||
supported_text_delta: overrides?.supported_text_delta ?? supportedTextDelta,
|
||||
pricing: {
|
||||
@ -97,7 +98,7 @@ const ModelEditContent: FC<ModelEditContentProps & ModalProps> = ({ provider, mo
|
||||
id: values.id || model.id,
|
||||
name: values.name || model.name,
|
||||
group: values.group || model.group,
|
||||
endpoint_type: provider.id === 'new-api' ? values.endpointType : model.endpoint_type,
|
||||
endpoint_type: isNewApiProvider(provider) ? values.endpointType : model.endpoint_type,
|
||||
capabilities: modelCapabilities,
|
||||
supported_text_delta: supportedTextDelta,
|
||||
pricing: {
|
||||
@ -247,7 +248,7 @@ const ModelEditContent: FC<ModelEditContentProps & ModalProps> = ({ provider, mo
|
||||
<Modal title={t('models.edit')} footer={null} transitionName="animation-move-down" centered {...props}>
|
||||
<Form
|
||||
form={form}
|
||||
labelCol={{ flex: provider.id === 'new-api' ? labelWidth : '110px' }}
|
||||
labelCol={{ flex: isNewApiProvider(provider) ? labelWidth : '110px' }}
|
||||
labelAlign="left"
|
||||
colon={false}
|
||||
style={{ marginTop: 15 }}
|
||||
@ -309,7 +310,7 @@ const ModelEditContent: FC<ModelEditContentProps & ModalProps> = ({ provider, mo
|
||||
tooltip={t('settings.models.add.group_name.tooltip')}>
|
||||
<Input placeholder={t('settings.models.add.group_name.placeholder')} spellCheck={false} />
|
||||
</Form.Item>
|
||||
{provider.id === 'new-api' && (
|
||||
{isNewApiProvider(provider) && (
|
||||
<Form.Item
|
||||
name="endpointType"
|
||||
label={t('settings.models.add.endpoint_type.label')}
|
||||
|
||||
@ -3,6 +3,7 @@ import ModelIdWithTags from '@renderer/components/ModelIdWithTags'
|
||||
import CustomTag from '@renderer/components/Tags/CustomTag'
|
||||
import { DynamicVirtualList } from '@renderer/components/VirtualList'
|
||||
import { getModelLogo } from '@renderer/config/models'
|
||||
import { isNewApiProvider } from '@renderer/config/providers'
|
||||
import FileItem from '@renderer/pages/files/FileItem'
|
||||
import NewApiBatchAddModelPopup from '@renderer/pages/settings/ProviderSettings/ModelList/NewApiBatchAddModelPopup'
|
||||
import { Model, Provider } from '@renderer/types'
|
||||
@ -91,7 +92,7 @@ const ManageModelsList: React.FC<ManageModelsListProps> = ({ modelGroups, provid
|
||||
// 添加整组
|
||||
const wouldAddModels = models.filter((model) => !isModelInProvider(provider, model.id))
|
||||
|
||||
if (provider.id === 'new-api') {
|
||||
if (isNewApiProvider(provider)) {
|
||||
if (wouldAddModels.every(isValidNewApiModel)) {
|
||||
wouldAddModels.forEach(onAddModel)
|
||||
} else {
|
||||
|
||||
@ -13,6 +13,7 @@ import {
|
||||
isWebSearchModel,
|
||||
SYSTEM_MODELS
|
||||
} from '@renderer/config/models'
|
||||
import { isNewApiProvider } from '@renderer/config/providers'
|
||||
import { useProvider } from '@renderer/hooks/useProvider'
|
||||
import NewApiAddModelPopup from '@renderer/pages/settings/ProviderSettings/ModelList/NewApiAddModelPopup'
|
||||
import NewApiBatchAddModelPopup from '@renderer/pages/settings/ProviderSettings/ModelList/NewApiBatchAddModelPopup'
|
||||
@ -129,7 +130,7 @@ const PopupContainer: React.FC<Props> = ({ providerId, resolve }) => {
|
||||
const onAddModel = useCallback(
|
||||
(model: Model) => {
|
||||
if (!isEmpty(model.name)) {
|
||||
if (provider.id === 'new-api') {
|
||||
if (isNewApiProvider(provider)) {
|
||||
if (model.supported_endpoint_types && model.supported_endpoint_types.length > 0) {
|
||||
addModel({
|
||||
...model,
|
||||
@ -160,7 +161,7 @@ const PopupContainer: React.FC<Props> = ({ providerId, resolve }) => {
|
||||
content: t('settings.models.manage.add_listed.confirm'),
|
||||
centered: true,
|
||||
onOk: () => {
|
||||
if (provider.id === 'new-api') {
|
||||
if (isNewApiProvider(provider)) {
|
||||
if (models.every(isValidNewApiModel)) {
|
||||
wouldAddModel.forEach(onAddModel)
|
||||
} else {
|
||||
|
||||
@ -2,7 +2,7 @@ import CollapsibleSearchBar from '@renderer/components/CollapsibleSearchBar'
|
||||
import { LoadingIcon, StreamlineGoodHealthAndWellBeing } from '@renderer/components/Icons'
|
||||
import { HStack } from '@renderer/components/Layout'
|
||||
import CustomTag from '@renderer/components/Tags/CustomTag'
|
||||
import { PROVIDER_URLS } from '@renderer/config/providers'
|
||||
import { isNewApiProvider, PROVIDER_URLS } from '@renderer/config/providers'
|
||||
import { useProvider } from '@renderer/hooks/useProvider'
|
||||
import { getProviderLabel } from '@renderer/i18n/label'
|
||||
import { SettingHelpLink, SettingHelpText, SettingHelpTextRow, SettingSubtitle } from '@renderer/pages/settings'
|
||||
@ -86,7 +86,7 @@ const ModelList: React.FC<ModelListProps> = ({ providerId }) => {
|
||||
}, [provider.id])
|
||||
|
||||
const onAddModel = useCallback(() => {
|
||||
if (provider.id === 'new-api') {
|
||||
if (isNewApiProvider(provider)) {
|
||||
NewApiAddModelPopup.show({ title: t('settings.models.add.add_model'), provider })
|
||||
} else {
|
||||
AddModelPopup.show({ title: t('settings.models.add.add_model'), provider })
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { TopView } from '@renderer/components/TopView'
|
||||
import { endpointTypeOptions } from '@renderer/config/endpointTypes'
|
||||
import { isNotSupportedTextDelta } from '@renderer/config/models'
|
||||
import { isNewApiProvider } from '@renderer/config/providers'
|
||||
import { useDynamicLabelWidth } from '@renderer/hooks/useDynamicLabelWidth'
|
||||
import { useProvider } from '@renderer/hooks/useProvider'
|
||||
import { EndpointType, Model, Provider } from '@renderer/types'
|
||||
@ -60,7 +61,7 @@ const PopupContainer: React.FC<Props> = ({ title, provider, resolve, model, endp
|
||||
provider: provider.id,
|
||||
name: values.name ? values.name : id.toUpperCase(),
|
||||
group: values.group ?? getDefaultGroupName(id),
|
||||
endpoint_type: provider.id === 'new-api' ? values.endpointType : undefined
|
||||
endpoint_type: isNewApiProvider(provider) ? values.endpointType : undefined
|
||||
}
|
||||
|
||||
addModel({ ...model, supported_text_delta: !isNotSupportedTextDelta(model) })
|
||||
|
||||
@ -2495,6 +2495,7 @@ const migrateConfig = {
|
||||
'157': (state: RootState) => {
|
||||
try {
|
||||
addProvider(state, 'aionly')
|
||||
state.llm.providers = moveProvider(state.llm.providers, 'aionly', 10)
|
||||
|
||||
const cherryinProvider = state.llm.providers.find((provider) => provider.id === 'cherryin')
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user