feat: implemented vision model support and ui enhancements.
- Updated color palette settings have been implemented. - Added VisionIcon component utilizing Ant Design icons and styled components for visual customization. - Updated vision model regex to include additional models. - Added support for multiple file columns in i18n resources. - Added translations to column titles. - Added support for vision models in the Select Model Button component. - Added functionality to display a vision model icon next to the model name on dropdown items. - Implemented changes to add vision model support to the Edit Models Popup. - Added icon to display vision models in provider settings.
This commit is contained in:
parent
71876e6a70
commit
617af8b12a
@ -24,9 +24,9 @@
|
|||||||
--color-background-soft: var(--color-black-soft);
|
--color-background-soft: var(--color-black-soft);
|
||||||
--color-background-mute: var(--color-black-mute);
|
--color-background-mute: var(--color-black-mute);
|
||||||
|
|
||||||
--color-primary: #135200;
|
--color-primary: #00b96b;
|
||||||
--color-primary-soft: #13520099;
|
--color-primary-soft: #00b96b99;
|
||||||
--color-primary-mute: #13520033;
|
--color-primary-mute: #00b96b33;
|
||||||
|
|
||||||
--color-text: var(--color-text-1);
|
--color-text: var(--color-text-1);
|
||||||
--color-icon: #ffffff99;
|
--color-icon: #ffffff99;
|
||||||
|
|||||||
15
src/renderer/src/components/Icons/VisionIcon.tsx
Normal file
15
src/renderer/src/components/Icons/VisionIcon.tsx
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { EyeOutlined } from '@ant-design/icons'
|
||||||
|
import React, { FC } from 'react'
|
||||||
|
import styled from 'styled-components'
|
||||||
|
|
||||||
|
const VisionIcon: FC<React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>> = (props) => {
|
||||||
|
return <Icon {...(props as any)} />
|
||||||
|
}
|
||||||
|
|
||||||
|
const Icon = styled(EyeOutlined)`
|
||||||
|
color: var(--color-primary);
|
||||||
|
font-size: 14px;
|
||||||
|
margin-left: 4px;
|
||||||
|
`
|
||||||
|
|
||||||
|
export default VisionIcon
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import { Model } from '@renderer/types'
|
import { Model } from '@renderer/types'
|
||||||
|
|
||||||
const TEXT_TO_IMAGE_REGEX = /flux|diffusion|stabilityai|sd-turbo|dall|cogview/i
|
const TEXT_TO_IMAGE_REGEX = /flux|diffusion|stabilityai|sd-turbo|dall|cogview/i
|
||||||
const VISION_REGEX = /llava|moondream|minicpm|gemini|claude|vision|glm-4v/i
|
const VISION_REGEX = /llava|moondream|minicpm|gemini-1.5|claude-3|vision|glm-4v|gpt-4|qwen-vl/i
|
||||||
const EMBEDDING_REGEX = /embedding/i
|
const EMBEDDING_REGEX = /embedding/i
|
||||||
|
|
||||||
export const SYSTEM_MODELS: Record<string, Model[]> = {
|
export const SYSTEM_MODELS: Record<string, Model[]> = {
|
||||||
|
|||||||
@ -103,7 +103,11 @@ const resources = {
|
|||||||
'assistant.search.placeholder': 'Search'
|
'assistant.search.placeholder': 'Search'
|
||||||
},
|
},
|
||||||
files: {
|
files: {
|
||||||
title: 'Files'
|
title: 'Files',
|
||||||
|
file: 'File',
|
||||||
|
name: 'Name',
|
||||||
|
size: 'Size',
|
||||||
|
created_at: 'Created At'
|
||||||
},
|
},
|
||||||
agents: {
|
agents: {
|
||||||
title: 'Assistants',
|
title: 'Assistants',
|
||||||
@ -362,7 +366,11 @@ const resources = {
|
|||||||
'assistant.search.placeholder': '搜索'
|
'assistant.search.placeholder': '搜索'
|
||||||
},
|
},
|
||||||
files: {
|
files: {
|
||||||
title: '文件'
|
title: '文件',
|
||||||
|
file: '文件',
|
||||||
|
name: '文件名',
|
||||||
|
size: '大小',
|
||||||
|
created_at: '创建时间'
|
||||||
},
|
},
|
||||||
agents: {
|
agents: {
|
||||||
title: '智能体',
|
title: '智能体',
|
||||||
|
|||||||
@ -24,23 +24,23 @@ const FilesPage: FC = () => {
|
|||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
title: 'File',
|
title: t('files.file'),
|
||||||
dataIndex: 'file',
|
dataIndex: 'file',
|
||||||
key: 'file'
|
key: 'file'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Name',
|
title: t('files.name'),
|
||||||
dataIndex: 'name',
|
dataIndex: 'name',
|
||||||
key: 'name'
|
key: 'name'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Size',
|
title: t('files.size'),
|
||||||
dataIndex: 'size',
|
dataIndex: 'size',
|
||||||
key: 'size',
|
key: 'size',
|
||||||
width: '100px'
|
width: '100px'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Created At',
|
title: t('files.created_at'),
|
||||||
dataIndex: 'created_at',
|
dataIndex: 'created_at',
|
||||||
key: 'created_at',
|
key: 'created_at',
|
||||||
width: '120px'
|
width: '120px'
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
import ModelAvatar from '@renderer/components/Avatar/ModelAvatar'
|
import ModelAvatar from '@renderer/components/Avatar/ModelAvatar'
|
||||||
|
import VisionIcon from '@renderer/components/Icons/VisionIcon'
|
||||||
import { isLocalAi } from '@renderer/config/env'
|
import { isLocalAi } from '@renderer/config/env'
|
||||||
|
import { isVisionModel } from '@renderer/config/models'
|
||||||
import { useAssistant } from '@renderer/hooks/useAssistant'
|
import { useAssistant } from '@renderer/hooks/useAssistant'
|
||||||
import { Assistant } from '@renderer/types'
|
import { Assistant } from '@renderer/types'
|
||||||
import { Button } from 'antd'
|
import { Button } from 'antd'
|
||||||
@ -27,6 +29,7 @@ const SelectModelButton: FC<Props> = ({ assistant }) => {
|
|||||||
<DropdownButton size="small" type="default">
|
<DropdownButton size="small" type="default">
|
||||||
<ModelAvatar model={model} size={20} />
|
<ModelAvatar model={model} size={20} />
|
||||||
<ModelName>{model ? upperFirst(model.name) : t('button.select_model')}</ModelName>
|
<ModelName>{model ? upperFirst(model.name) : t('button.select_model')}</ModelName>
|
||||||
|
{isVisionModel(model) && <VisionIcon style={{ marginLeft: 0 }} />}
|
||||||
</DropdownButton>
|
</DropdownButton>
|
||||||
</SelectModelDropdown>
|
</SelectModelDropdown>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import VisionIcon from '@renderer/components/Icons/VisionIcon'
|
||||||
|
import { isVisionModel } from '@renderer/config/models'
|
||||||
import { getModelLogo } from '@renderer/config/provider'
|
import { getModelLogo } from '@renderer/config/provider'
|
||||||
import { useProviders } from '@renderer/hooks/useProvider'
|
import { useProviders } from '@renderer/hooks/useProvider'
|
||||||
import { getModelUniqId } from '@renderer/services/model'
|
import { getModelUniqId } from '@renderer/services/model'
|
||||||
@ -25,7 +27,11 @@ const SelectModelDropdown: FC<Props & PropsWithChildren> = ({ children, model, o
|
|||||||
type: 'group',
|
type: 'group',
|
||||||
children: reverse(sortBy(p.models, 'name')).map((m) => ({
|
children: reverse(sortBy(p.models, 'name')).map((m) => ({
|
||||||
key: getModelUniqId(m),
|
key: getModelUniqId(m),
|
||||||
label: upperFirst(m?.name),
|
label: (
|
||||||
|
<div>
|
||||||
|
{upperFirst(m?.name)} {isVisionModel(m) && <VisionIcon />}
|
||||||
|
</div>
|
||||||
|
),
|
||||||
defaultSelectedKeys: model ? [getModelUniqId(model)] : [],
|
defaultSelectedKeys: model ? [getModelUniqId(model)] : [],
|
||||||
icon: (
|
icon: (
|
||||||
<Avatar src={getModelLogo(m?.id || '')} size={24}>
|
<Avatar src={getModelLogo(m?.id || '')} size={24}>
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { LoadingOutlined, MinusOutlined, PlusOutlined, QuestionCircleOutlined } from '@ant-design/icons'
|
import { LoadingOutlined, MinusOutlined, PlusOutlined, QuestionCircleOutlined } from '@ant-design/icons'
|
||||||
import { SYSTEM_MODELS } from '@renderer/config/models'
|
import VisionIcon from '@renderer/components/Icons/VisionIcon'
|
||||||
|
import { isVisionModel, SYSTEM_MODELS } from '@renderer/config/models'
|
||||||
import { getModelLogo } from '@renderer/config/provider'
|
import { getModelLogo } from '@renderer/config/provider'
|
||||||
import { useProvider } from '@renderer/hooks/useProvider'
|
import { useProvider } from '@renderer/hooks/useProvider'
|
||||||
import { fetchModels } from '@renderer/services/api'
|
import { fetchModels } from '@renderer/services/api'
|
||||||
@ -126,6 +127,7 @@ const PopupContainer: React.FC<Props> = ({ provider: _provider, resolve }) => {
|
|||||||
</Avatar>
|
</Avatar>
|
||||||
<ListItemName>
|
<ListItemName>
|
||||||
{model.name}
|
{model.name}
|
||||||
|
{isVisionModel(model) && <VisionIcon />}
|
||||||
{isFreeModel(model) && (
|
{isFreeModel(model) && (
|
||||||
<Tag style={{ marginLeft: 10 }} color="green">
|
<Tag style={{ marginLeft: 10 }} color="green">
|
||||||
Free
|
Free
|
||||||
|
|||||||
@ -6,6 +6,8 @@ import {
|
|||||||
MinusCircleOutlined,
|
MinusCircleOutlined,
|
||||||
PlusOutlined
|
PlusOutlined
|
||||||
} from '@ant-design/icons'
|
} from '@ant-design/icons'
|
||||||
|
import VisionIcon from '@renderer/components/Icons/VisionIcon'
|
||||||
|
import { isVisionModel } from '@renderer/config/models'
|
||||||
import { getModelLogo } from '@renderer/config/provider'
|
import { getModelLogo } from '@renderer/config/provider'
|
||||||
import { PROVIDER_CONFIG } from '@renderer/config/provider'
|
import { PROVIDER_CONFIG } from '@renderer/config/provider'
|
||||||
import { useTheme } from '@renderer/context/ThemeProvider'
|
import { useTheme } from '@renderer/context/ThemeProvider'
|
||||||
@ -148,7 +150,7 @@ const ProviderSetting: FC<Props> = ({ provider: _provider }) => {
|
|||||||
<Avatar src={getModelLogo(model.id)} size={22} style={{ marginRight: '8px' }}>
|
<Avatar src={getModelLogo(model.id)} size={22} style={{ marginRight: '8px' }}>
|
||||||
{model.name[0].toUpperCase()}
|
{model.name[0].toUpperCase()}
|
||||||
</Avatar>
|
</Avatar>
|
||||||
{model.name}
|
{model.name} {isVisionModel(model) && <VisionIcon />}
|
||||||
</ModelListHeader>
|
</ModelListHeader>
|
||||||
<RemoveIcon onClick={() => removeModel(model)} />
|
<RemoveIcon onClick={() => removeModel(model)} />
|
||||||
</ModelListItem>
|
</ModelListItem>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user