mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-19 14:41:24 +08:00
feat: add CherryIN API host selection settings (#11797)
feat(provider): add CherryIN settings and migration support - Introduced CherryINSettings component for configuring CherryIN API hosts. - Updated ProviderSetting to conditionally render CherryINSettings based on provider ID and user language. - Enhanced providerToAiSdkConfig to include CherryIN API host URLs. - Incremented store version to 183 and added migration logic to set default CherryIN API hosts.
This commit is contained in:
parent
96085707ce
commit
76524d68c6
@ -9,6 +9,7 @@ import {
|
||||
} from '@renderer/hooks/useAwsBedrock'
|
||||
import { createVertexProvider, isVertexAIConfigured } from '@renderer/hooks/useVertexAI'
|
||||
import { getProviderByModel } from '@renderer/services/AssistantService'
|
||||
import { getProviderById } from '@renderer/services/ProviderService'
|
||||
import store from '@renderer/store'
|
||||
import { isSystemProvider, type Model, type Provider, SystemProviderIds } from '@renderer/types'
|
||||
import type { OpenAICompletionsStreamOptions } from '@renderer/types/aiCoreTypes'
|
||||
@ -250,6 +251,12 @@ export function providerToAiSdkConfig(actualProvider: Provider, model: Model): A
|
||||
if (model.endpoint_type) {
|
||||
extraOptions.endpointType = model.endpoint_type
|
||||
}
|
||||
// CherryIN API Host
|
||||
const cherryinProvider = getProviderById(SystemProviderIds.cherryin)
|
||||
if (cherryinProvider) {
|
||||
extraOptions.anthropicBaseURL = cherryinProvider.anthropicApiHost
|
||||
extraOptions.geminiBaseURL = cherryinProvider.apiHost + '/gemini/v1beta'
|
||||
}
|
||||
}
|
||||
|
||||
if (hasProviderConfig(aiSdkProviderId) && aiSdkProviderId !== 'openai-compatible') {
|
||||
|
||||
@ -0,0 +1,74 @@
|
||||
import { useProvider } from '@renderer/hooks/useProvider'
|
||||
import { Select } from 'antd'
|
||||
import type { FC } from 'react'
|
||||
import { useCallback, useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
interface CherryINSettingsProps {
|
||||
providerId: string
|
||||
apiHost: string
|
||||
setApiHost: (host: string) => void
|
||||
}
|
||||
|
||||
const API_HOST_OPTIONS = [
|
||||
{
|
||||
value: 'https://open.cherryin.cc',
|
||||
labelKey: '加速域名',
|
||||
description: 'open.cherryin.cc'
|
||||
},
|
||||
{
|
||||
value: 'https://open.cherryin.net',
|
||||
labelKey: '国际域名',
|
||||
description: 'open.cherryin.net'
|
||||
},
|
||||
{
|
||||
value: 'https://open.cherryin.ai',
|
||||
labelKey: '备用域名',
|
||||
description: 'open.cherryin.ai'
|
||||
}
|
||||
]
|
||||
|
||||
const CherryINSettings: FC<CherryINSettingsProps> = ({ providerId, apiHost, setApiHost }) => {
|
||||
const { updateProvider } = useProvider(providerId)
|
||||
const { t } = useTranslation()
|
||||
|
||||
const getCurrentHost = useMemo(() => {
|
||||
const matchedOption = API_HOST_OPTIONS.find((option) => apiHost?.includes(option.value.replace('https://', '')))
|
||||
return matchedOption?.value ?? API_HOST_OPTIONS[0].value
|
||||
}, [apiHost])
|
||||
|
||||
const handleHostChange = useCallback(
|
||||
(value: string) => {
|
||||
setApiHost(value)
|
||||
updateProvider({ apiHost: value, anthropicApiHost: value })
|
||||
},
|
||||
[setApiHost, updateProvider]
|
||||
)
|
||||
|
||||
const options = useMemo(
|
||||
() =>
|
||||
API_HOST_OPTIONS.map((option) => ({
|
||||
value: option.value,
|
||||
label: (
|
||||
<div className="flex flex-col gap-0.5">
|
||||
<span>{t(option.labelKey)}</span>
|
||||
<span className="text-[var(--color-text-3)] text-xs">{t(option.description)}</span>
|
||||
</div>
|
||||
)
|
||||
})),
|
||||
[t]
|
||||
)
|
||||
|
||||
return (
|
||||
<Select
|
||||
value={getCurrentHost}
|
||||
onChange={handleHostChange}
|
||||
options={options}
|
||||
style={{ width: '100%', marginTop: 5 }}
|
||||
optionLabelProp="label"
|
||||
labelRender={(option) => option.value}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default CherryINSettings
|
||||
@ -10,7 +10,6 @@ import { PROVIDER_URLS } from '@renderer/config/providers'
|
||||
import { useTheme } from '@renderer/context/ThemeProvider'
|
||||
import { useAllProviders, useProvider, useProviders } from '@renderer/hooks/useProvider'
|
||||
import { useTimer } from '@renderer/hooks/useTimer'
|
||||
import i18n from '@renderer/i18n'
|
||||
import AnthropicSettings from '@renderer/pages/settings/ProviderSettings/AnthropicSettings'
|
||||
import { ModelList } from '@renderer/pages/settings/ProviderSettings/ModelList'
|
||||
import { checkApi } from '@renderer/services/ApiService'
|
||||
@ -53,6 +52,7 @@ import {
|
||||
} from '..'
|
||||
import ApiOptionsSettingsPopup from './ApiOptionsSettings/ApiOptionsSettingsPopup'
|
||||
import AwsBedrockSettings from './AwsBedrockSettings'
|
||||
import CherryINSettings from './CherryINSettings'
|
||||
import CustomHeaderPopup from './CustomHeaderPopup'
|
||||
import DMXAPISettings from './DMXAPISettings'
|
||||
import GithubCopilotSettings from './GithubCopilotSettings'
|
||||
@ -99,13 +99,15 @@ const ProviderSetting: FC<Props> = ({ providerId }) => {
|
||||
const [anthropicApiHost, setAnthropicHost] = useState<string | undefined>(provider.anthropicApiHost)
|
||||
const [apiVersion, setApiVersion] = useState(provider.apiVersion)
|
||||
const [activeHostField, setActiveHostField] = useState<HostField>('apiHost')
|
||||
const { t } = useTranslation()
|
||||
const { t, i18n } = useTranslation()
|
||||
const { theme } = useTheme()
|
||||
const { setTimeoutTimer } = useTimer()
|
||||
const dispatch = useAppDispatch()
|
||||
|
||||
const isAzureOpenAI = isAzureOpenAIProvider(provider)
|
||||
const isDmxapi = provider.id === 'dmxapi'
|
||||
const isCherryIN = provider.id === 'cherryin'
|
||||
const isChineseUser = i18n.language.startsWith('zh')
|
||||
const noAPIInputProviders = ['aws-bedrock'] as const satisfies SystemProviderId[]
|
||||
const hideApiInput = noAPIInputProviders.some((id) => id === provider.id)
|
||||
const noAPIKeyInputProviders = ['copilot', 'vertexai'] as const satisfies SystemProviderId[]
|
||||
@ -338,13 +340,16 @@ const ProviderSetting: FC<Props> = ({ providerId }) => {
|
||||
}, [provider.anthropicApiHost])
|
||||
|
||||
const canConfigureAnthropicHost = useMemo(() => {
|
||||
if (isCherryIN) {
|
||||
return false
|
||||
}
|
||||
if (isNewApiProvider(provider)) {
|
||||
return true
|
||||
}
|
||||
return (
|
||||
provider.type !== 'anthropic' && isSystemProviderId(provider.id) && isAnthropicCompatibleProviderId(provider.id)
|
||||
)
|
||||
}, [provider])
|
||||
}, [isCherryIN, provider])
|
||||
|
||||
const anthropicHostPreview = useMemo(() => {
|
||||
const rawHost = anthropicApiHost ?? provider.anthropicApiHost
|
||||
@ -513,6 +518,9 @@ const ProviderSetting: FC<Props> = ({ providerId }) => {
|
||||
</SettingSubtitle>
|
||||
{activeHostField === 'apiHost' && (
|
||||
<>
|
||||
{isCherryIN && isChineseUser ? (
|
||||
<CherryINSettings providerId={provider.id} apiHost={apiHost} setApiHost={setApiHost} />
|
||||
) : (
|
||||
<Space.Compact style={{ width: '100%', marginTop: 5 }}>
|
||||
<Input
|
||||
value={apiHost}
|
||||
@ -526,6 +534,7 @@ const ProviderSetting: FC<Props> = ({ providerId }) => {
|
||||
</Button>
|
||||
)}
|
||||
</Space.Compact>
|
||||
)}
|
||||
{isVertexProvider(provider) && (
|
||||
<SettingHelpTextRow>
|
||||
<SettingHelpText>{t('settings.provider.vertex_ai.api_host_help')}</SettingHelpText>
|
||||
|
||||
@ -67,7 +67,7 @@ const persistedReducer = persistReducer(
|
||||
{
|
||||
key: 'cherry-studio',
|
||||
storage,
|
||||
version: 182,
|
||||
version: 183,
|
||||
blacklist: ['runtime', 'messages', 'messageBlocks', 'tabs', 'toolPermissions'],
|
||||
migrate
|
||||
},
|
||||
|
||||
@ -2976,6 +2976,22 @@ const migrateConfig = {
|
||||
logger.error('migrate 182 error', error as Error)
|
||||
return state
|
||||
}
|
||||
},
|
||||
'183': (state: RootState) => {
|
||||
try {
|
||||
state.llm.providers.forEach((provider) => {
|
||||
if (provider.id === SystemProviderIds.cherryin) {
|
||||
provider.apiHost = 'https://open.cherryin.cc'
|
||||
provider.anthropicApiHost = 'https://open.cherryin.cc'
|
||||
}
|
||||
})
|
||||
state.llm.providers = moveProvider(state.llm.providers, SystemProviderIds.poe, 10)
|
||||
logger.info('migrate 183 success')
|
||||
return state
|
||||
} catch (error) {
|
||||
logger.error('migrate 183 error', error as Error)
|
||||
return state
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user