mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-28 21:42:27 +08:00
feat(ProviderSettings): add API options settings and popup for providers
- Introduced ApiOptionsSettings component to manage API options for providers. - Added ApiOptionsSettingsPopup for displaying API options in a modal. - Updated ProviderSetting to include a button for opening the API options popup for non-system providers. - Refactored imports and adjusted layout in ProviderSetting for better UI consistency.
This commit is contained in:
parent
ef57e543c6
commit
793ccf978e
@ -1,8 +1,8 @@
|
||||
import InfoTooltip from '@renderer/components/InfoTooltip'
|
||||
import { HStack } from '@renderer/components/Layout'
|
||||
import { useProvider } from '@renderer/hooks/useProvider'
|
||||
import { isSystemProvider, Provider } from '@renderer/types'
|
||||
import { Collapse, Flex, Switch } from 'antd'
|
||||
import { Provider } from '@renderer/types'
|
||||
import { Flex, Switch } from 'antd'
|
||||
import { startTransition, useCallback, useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
@ -55,17 +55,6 @@ const ApiOptionsSettings = ({ providerId }: Props) => {
|
||||
},
|
||||
checked: !provider.apiOptions?.isNotSupportStreamOptions
|
||||
},
|
||||
{
|
||||
key: 'openai_array_content',
|
||||
label: t('settings.provider.api.options.array_content.label'),
|
||||
tip: t('settings.provider.api.options.array_content.help'),
|
||||
onChange: (checked: boolean) => {
|
||||
updateProviderTransition({
|
||||
apiOptions: { ...provider.apiOptions, isNotSupportArrayContent: !checked }
|
||||
})
|
||||
},
|
||||
checked: !provider.apiOptions?.isNotSupportArrayContent
|
||||
},
|
||||
{
|
||||
key: 'openai_service_tier',
|
||||
label: t('settings.provider.api.options.service_tier.label'),
|
||||
@ -93,64 +82,41 @@ const ApiOptionsSettings = ({ providerId }: Props) => {
|
||||
)
|
||||
|
||||
const options = useMemo(() => {
|
||||
const items: OptionType[] = []
|
||||
const items: OptionType[] = [
|
||||
{
|
||||
key: 'openai_array_content',
|
||||
label: t('settings.provider.api.options.array_content.label'),
|
||||
tip: t('settings.provider.api.options.array_content.help'),
|
||||
onChange: (checked: boolean) => {
|
||||
updateProviderTransition({
|
||||
apiOptions: { ...provider.apiOptions, isNotSupportArrayContent: !checked }
|
||||
})
|
||||
},
|
||||
checked: !provider.apiOptions?.isNotSupportArrayContent
|
||||
}
|
||||
]
|
||||
|
||||
if (provider.type === 'openai' || provider.type === 'openai-response' || provider.type === 'azure-openai') {
|
||||
items.push(...openAIOptions)
|
||||
}
|
||||
return items
|
||||
}, [openAIOptions, provider.type])
|
||||
|
||||
if (options.length === 0 || isSystemProvider(provider)) {
|
||||
return null
|
||||
}
|
||||
return items
|
||||
}, [openAIOptions, provider.apiOptions, provider.type, t, updateProviderTransition])
|
||||
|
||||
return (
|
||||
<>
|
||||
<Collapse
|
||||
items={[
|
||||
{
|
||||
key: 'settings',
|
||||
styles: {
|
||||
header: {
|
||||
paddingLeft: 0,
|
||||
paddingRight: 6
|
||||
},
|
||||
body: {
|
||||
padding: 0
|
||||
}
|
||||
},
|
||||
label: (
|
||||
<div
|
||||
style={{
|
||||
fontSize: 14,
|
||||
color: 'var(--color-text-1)',
|
||||
userSelect: 'none',
|
||||
fontWeight: 'bold'
|
||||
}}>
|
||||
{t('settings.provider.api.options.label')}
|
||||
</div>
|
||||
),
|
||||
children: (
|
||||
<Flex vertical gap="middle">
|
||||
{options.map((item) => (
|
||||
<HStack key={item.key} justifyContent="space-between">
|
||||
<HStack alignItems="center" gap={6}>
|
||||
<label style={{ cursor: 'pointer' }} htmlFor={item.key}>
|
||||
{item.label}
|
||||
</label>
|
||||
<InfoTooltip title={item.tip}></InfoTooltip>
|
||||
</HStack>
|
||||
<Switch id={item.key} checked={item.checked} onChange={item.onChange} />
|
||||
</HStack>
|
||||
))}
|
||||
</Flex>
|
||||
)
|
||||
}
|
||||
]}
|
||||
ghost
|
||||
expandIconPosition="end"
|
||||
/>
|
||||
</>
|
||||
<Flex vertical gap="middle">
|
||||
{options.map((item) => (
|
||||
<HStack key={item.key} justifyContent="space-between">
|
||||
<HStack alignItems="center" gap={6}>
|
||||
<label style={{ cursor: 'pointer' }} htmlFor={item.key}>
|
||||
{item.label}
|
||||
</label>
|
||||
<InfoTooltip title={item.tip}></InfoTooltip>
|
||||
</HStack>
|
||||
<Switch id={item.key} checked={item.checked} onChange={item.onChange} />
|
||||
</HStack>
|
||||
))}
|
||||
</Flex>
|
||||
)
|
||||
}
|
||||
|
||||
@ -0,0 +1,71 @@
|
||||
import { TopView } from '@renderer/components/TopView'
|
||||
import { Modal } from 'antd'
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import ApiOptionsSettings from './ApiOptionsSettings'
|
||||
|
||||
interface ShowParams {
|
||||
providerId: string
|
||||
}
|
||||
|
||||
interface Props extends ShowParams {
|
||||
resolve: (data: any) => void
|
||||
}
|
||||
|
||||
const PopupContainer: React.FC<Props> = ({ providerId, resolve }) => {
|
||||
const { t } = useTranslation()
|
||||
const [open, setOpen] = useState(true)
|
||||
|
||||
const onOk = () => {
|
||||
setOpen(false)
|
||||
}
|
||||
|
||||
const onCancel = () => {
|
||||
setOpen(false)
|
||||
}
|
||||
|
||||
const onClose = () => {
|
||||
resolve({})
|
||||
}
|
||||
|
||||
ApiOptionsSettingsPopup.hide = onCancel
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={t('settings.provider.api.options.label')}
|
||||
open={open}
|
||||
onOk={onOk}
|
||||
onCancel={onCancel}
|
||||
afterClose={onClose}
|
||||
transitionName="animation-move-down"
|
||||
styles={{ body: { padding: '20px 16px' } }}
|
||||
footer={null}
|
||||
centered>
|
||||
<ApiOptionsSettings providerId={providerId} />
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
const TopViewKey = 'ApiOptionsSettingsPopup'
|
||||
|
||||
export default class ApiOptionsSettingsPopup {
|
||||
static topviewId = 0
|
||||
static hide() {
|
||||
TopView.hide(TopViewKey)
|
||||
}
|
||||
static show(props: ShowParams) {
|
||||
return new Promise<any>((resolve) => {
|
||||
TopView.show(
|
||||
<PopupContainer
|
||||
{...props}
|
||||
resolve={(v) => {
|
||||
resolve(v)
|
||||
TopView.hide(TopViewKey)
|
||||
}}
|
||||
/>,
|
||||
TopViewKey
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -12,7 +12,7 @@ import ManageModelsPopup from '@renderer/pages/settings/ProviderSettings/ModelLi
|
||||
import NewApiAddModelPopup from '@renderer/pages/settings/ProviderSettings/ModelList/NewApiAddModelPopup'
|
||||
import { Model } from '@renderer/types'
|
||||
import { filterModelsByKeywords } from '@renderer/utils'
|
||||
import { Button, Empty, Flex, Spin, Tooltip } from 'antd'
|
||||
import { Button, Flex, Spin, Tooltip } from 'antd'
|
||||
import { groupBy, isEmpty, sortBy, toPairs } from 'lodash'
|
||||
import { ListCheck, Plus } from 'lucide-react'
|
||||
import React, { memo, startTransition, useCallback, useEffect, useMemo, useState } from 'react'
|
||||
@ -120,7 +120,7 @@ const ModelList: React.FC<ModelListProps> = ({ providerId }) => {
|
||||
</HStack>
|
||||
</SettingSubtitle>
|
||||
<Spin spinning={isLoading} indicator={<LoadingIcon color="var(--color-text-2)" />}>
|
||||
{displayedModelGroups && !isEmpty(displayedModelGroups) ? (
|
||||
{displayedModelGroups && !isEmpty(displayedModelGroups) && (
|
||||
<Flex gap={12} vertical>
|
||||
{Object.keys(displayedModelGroups).map((group, i) => (
|
||||
<ModelListGroup
|
||||
@ -135,12 +135,6 @@ const ModelList: React.FC<ModelListProps> = ({ providerId }) => {
|
||||
/>
|
||||
))}
|
||||
</Flex>
|
||||
) : (
|
||||
<Empty
|
||||
image={Empty.PRESENTED_IMAGE_SIMPLE}
|
||||
description={t('settings.models.empty')}
|
||||
style={{ visibility: isLoading ? 'hidden' : 'visible' }}
|
||||
/>
|
||||
)}
|
||||
</Spin>
|
||||
<Flex justify="space-between" align="center">
|
||||
|
||||
@ -10,13 +10,14 @@ import i18n from '@renderer/i18n'
|
||||
import { ModelList } from '@renderer/pages/settings/ProviderSettings/ModelList'
|
||||
import { checkApi } from '@renderer/services/ApiService'
|
||||
import { isProviderSupportAuth } from '@renderer/services/ProviderService'
|
||||
import { isSystemProvider } from '@renderer/types'
|
||||
import { ApiKeyConnectivity, HealthStatus } from '@renderer/types/healthCheck'
|
||||
import { formatApiHost, formatApiKeys, getFancyProviderName, isOpenAIProvider } from '@renderer/utils'
|
||||
import { formatErrorMessage } from '@renderer/utils/error'
|
||||
import { Button, Divider, Flex, Input, Space, Switch, Tooltip } from 'antd'
|
||||
import Link from 'antd/es/typography/Link'
|
||||
import { debounce, isEmpty } from 'lodash'
|
||||
import { Check, Settings2, SquareArrowOutUpRight, TriangleAlert } from 'lucide-react'
|
||||
import { Bolt, Check, Settings2, SquareArrowOutUpRight, TriangleAlert } from 'lucide-react'
|
||||
import { FC, useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import styled from 'styled-components'
|
||||
@ -29,7 +30,7 @@ import {
|
||||
SettingSubtitle,
|
||||
SettingTitle
|
||||
} from '..'
|
||||
import ApiOptionsSettings from './ApiOptionsSettings'
|
||||
import ApiOptionsSettingsPopup from './ApiOptionsSettings/ApiOptionsSettingsPopup'
|
||||
import AwsBedrockSettings from './AwsBedrockSettings'
|
||||
import CustomHeaderPopup from './CustomHeaderPopup'
|
||||
import DMXAPISettings from './DMXAPISettings'
|
||||
@ -229,13 +230,21 @@ const ProviderSetting: FC<Props> = ({ providerId }) => {
|
||||
return (
|
||||
<SettingContainer theme={theme} style={{ background: 'var(--color-background)' }}>
|
||||
<SettingTitle>
|
||||
<Flex align="center" gap={5}>
|
||||
<Flex align="center" gap={8}>
|
||||
<ProviderName>{fancyProviderName}</ProviderName>
|
||||
{officialWebsite && (
|
||||
<Link target="_blank" href={providerConfig.websites.official} style={{ display: 'flex' }}>
|
||||
<Button type="text" size="small" icon={<SquareArrowOutUpRight size={14} />} />
|
||||
</Link>
|
||||
)}
|
||||
{!isSystemProvider(provider) && (
|
||||
<Button
|
||||
type="text"
|
||||
icon={<Bolt size={14} />}
|
||||
size="small"
|
||||
onClick={() => ApiOptionsSettingsPopup.show({ providerId: provider.id })}
|
||||
/>
|
||||
)}
|
||||
</Flex>
|
||||
<Switch
|
||||
value={provider.enabled}
|
||||
@ -366,7 +375,6 @@ const ProviderSetting: FC<Props> = ({ providerId }) => {
|
||||
{provider.id === 'copilot' && <GithubCopilotSettings providerId={provider.id} />}
|
||||
{provider.id === 'aws-bedrock' && <AwsBedrockSettings />}
|
||||
{provider.id === 'vertexai' && <VertexAISettings providerId={provider.id} />}
|
||||
<ApiOptionsSettings providerId={provider.id} />
|
||||
<ModelList providerId={provider.id} />
|
||||
</SettingContainer>
|
||||
)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user