mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-26 11:44:28 +08:00
feat(AgentSettings): add model selection to essential settings
- Make model prop optional in ModelAvatar component - Ensure models array always returns an array in useModels hook - Export SelectorProps type for reuse - Add getProviderNameById utility function - Introduce ModelLabel component for displaying model info - Update AgentEssentialSettings to include model selection dropdown
This commit is contained in:
parent
f49d3791b6
commit
f45b744318
@ -5,7 +5,7 @@ import { first } from 'lodash'
|
||||
import { FC } from 'react'
|
||||
|
||||
interface Props {
|
||||
model: Model
|
||||
model?: Model
|
||||
size: number
|
||||
props?: AvatarProps
|
||||
className?: string
|
||||
|
||||
@ -34,7 +34,7 @@ interface MultipleSelectorProps<V> extends BaseSelectorProps<V> {
|
||||
onChange: (value: V[]) => void
|
||||
}
|
||||
|
||||
type SelectorProps<V> = SingleSelectorProps<V> | MultipleSelectorProps<V>
|
||||
export type SelectorProps<V> = SingleSelectorProps<V> | MultipleSelectorProps<V>
|
||||
|
||||
const Selector = <V extends string | number>({
|
||||
options,
|
||||
|
||||
@ -12,7 +12,7 @@ export const useModels = (filter?: ApiModelsFilter) => {
|
||||
}, [client, filter])
|
||||
const { data, error, isLoading } = useSWR(path, fetcher)
|
||||
return {
|
||||
models: data?.data,
|
||||
models: data?.data ?? [],
|
||||
error,
|
||||
isLoading
|
||||
}
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
import { HStack } from '@renderer/components/Layout'
|
||||
import { useModels } from '@renderer/hooks/agents/useModels'
|
||||
import { useUpdateAgent } from '@renderer/hooks/agents/useUpdateAgent'
|
||||
import { AgentEntity, UpdateAgentForm } from '@renderer/types'
|
||||
import { Input } from 'antd'
|
||||
import { FC, useState } from 'react'
|
||||
import { Input, Select } from 'antd'
|
||||
import { DefaultOptionType } from 'antd/es/select'
|
||||
import { FC, useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import { AgentLabel, SettingsContainer, SettingsItem, SettingsTitle } from './shared'
|
||||
import { AgentLabel, ModelLabel, SettingsContainer, SettingsItem, SettingsTitle } from './shared'
|
||||
|
||||
interface AgentEssentialSettingsProps {
|
||||
agent: AgentEntity | undefined | null
|
||||
@ -15,6 +16,7 @@ interface AgentEssentialSettingsProps {
|
||||
const AgentEssentialSettings: FC<AgentEssentialSettingsProps> = ({ agent, update }) => {
|
||||
const { t } = useTranslation()
|
||||
const [name, setName] = useState<string>((agent?.name ?? '').trim())
|
||||
const { models } = useModels({ providerType: 'anthropic' })
|
||||
|
||||
const onUpdate = () => {
|
||||
if (!agent) return
|
||||
@ -22,6 +24,13 @@ const AgentEssentialSettings: FC<AgentEssentialSettingsProps> = ({ agent, update
|
||||
update(_agent)
|
||||
}
|
||||
|
||||
const modelOptions = useMemo(() => {
|
||||
return models.map((model) => ({
|
||||
value: model.id,
|
||||
label: <ModelLabel model={model} />
|
||||
})) satisfies DefaultOptionType[]
|
||||
}, [models])
|
||||
|
||||
if (!agent) return null
|
||||
|
||||
return (
|
||||
@ -30,21 +39,27 @@ const AgentEssentialSettings: FC<AgentEssentialSettingsProps> = ({ agent, update
|
||||
<SettingsTitle>{t('agent.type.label')}</SettingsTitle>
|
||||
<AgentLabel type={agent.type} />
|
||||
</SettingsItem>
|
||||
<SettingsItem>
|
||||
<SettingsItem inline>
|
||||
<SettingsTitle>{t('common.name')}</SettingsTitle>
|
||||
<HStack gap={8} alignItems="center">
|
||||
<Input
|
||||
placeholder={t('common.assistant') + t('common.name')}
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
onBlur={() => {
|
||||
if (name !== agent.name) {
|
||||
onUpdate()
|
||||
}
|
||||
}}
|
||||
style={{ flex: 1 }}
|
||||
/>
|
||||
</HStack>
|
||||
<Input
|
||||
placeholder={t('common.agent_one') + t('common.name')}
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
onBlur={() => {
|
||||
if (name !== agent.name) {
|
||||
onUpdate()
|
||||
}
|
||||
}}
|
||||
className="max-w-80 flex-1"
|
||||
/>
|
||||
</SettingsItem>
|
||||
<SettingsItem inline className="gap-8">
|
||||
<SettingsTitle>{t('common.model')}</SettingsTitle>
|
||||
<Select
|
||||
options={modelOptions}
|
||||
className="max-w-80 flex-1"
|
||||
placeholder={t('common.placeholders.select.model')}
|
||||
/>
|
||||
</SettingsItem>
|
||||
</SettingsContainer>
|
||||
)
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import { Avatar, AvatarProps, cn } from '@heroui/react'
|
||||
import { getAgentAvatar } from '@renderer/config/agent'
|
||||
import { getModelLogo } from '@renderer/config/models'
|
||||
import { getAgentTypeLabel } from '@renderer/i18n/label'
|
||||
import { AgentType } from '@renderer/types'
|
||||
import { AgentType, ApiModel } from '@renderer/types'
|
||||
import React from 'react'
|
||||
|
||||
import { SettingDivider } from '..'
|
||||
@ -48,7 +49,7 @@ export const SettingsItem: React.FC<SettingsItemProps> = ({
|
||||
<>
|
||||
<div
|
||||
{...props}
|
||||
className={cn('flex flex-col', inline ? 'flex-row items-center justify-between gap-2' : undefined, className)}>
|
||||
className={cn('flex flex-col', inline ? 'flex-row items-center justify-between gap-4' : undefined, className)}>
|
||||
{children}
|
||||
</div>
|
||||
{divider && <SettingDivider />}
|
||||
@ -63,3 +64,18 @@ export const SettingsContainer: React.FC<React.ComponentPropsWithRef<'div'>> = (
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export interface ModelLabelProps extends Omit<React.ComponentPropsWithRef<'div'>, 'children'> {
|
||||
model: ApiModel
|
||||
}
|
||||
|
||||
export const ModelLabel: React.FC<ModelLabelProps> = ({ model, className, ...props }) => {
|
||||
return (
|
||||
<div className={cn('flex items-center gap-1', className)} {...props}>
|
||||
<Avatar src={getModelLogo(model.id)} className="h-4 w-4" />
|
||||
<span>
|
||||
{model.name} | {model.provider_name}
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -12,6 +12,15 @@ export function getProviderName(model?: Model) {
|
||||
return getFancyProviderName(provider)
|
||||
}
|
||||
|
||||
export function getProviderNameById(pid: string) {
|
||||
const provider = store.getState().llm.providers.find((p) => p.id === pid)
|
||||
if (provider) {
|
||||
return getFancyProviderName(provider)
|
||||
} else {
|
||||
return 'Unknown Provider'
|
||||
}
|
||||
}
|
||||
|
||||
export function getProviderByModel(model?: Model) {
|
||||
const id = model?.provider
|
||||
const provider = store.getState().llm.providers.find((p) => p.id === id)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user