feat: Enhance model tags and icons with new reasoning and visual styles
This commit is contained in:
parent
a27150c154
commit
9aa829e6fc
@ -1,91 +1,96 @@
|
||||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 4753420 */
|
||||
src: url('iconfont.woff2?t=1736309723926') format('woff2'),
|
||||
url('iconfont.woff?t=1736309723926') format('woff'),
|
||||
url('iconfont.ttf?t=1736309723926') format('truetype');
|
||||
font-family: 'iconfont'; /* Project id 4753420 */
|
||||
src: url('iconfont.woff2?t=1738750230250') format('woff2');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
font-family: "iconfont" !important;
|
||||
font-family: 'iconfont' !important;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-thinking:before {
|
||||
content: '\e65b';
|
||||
}
|
||||
|
||||
.icon-at:before {
|
||||
content: "\e623";
|
||||
content: '\e623';
|
||||
}
|
||||
|
||||
.icon-icon-adaptive-width:before {
|
||||
content: "\e87a";
|
||||
content: '\e87a';
|
||||
}
|
||||
|
||||
.icon-at1:before {
|
||||
content: '\e630';
|
||||
}
|
||||
|
||||
.icon-a-darkmode:before {
|
||||
content: "\e6cd";
|
||||
content: '\e6cd';
|
||||
}
|
||||
|
||||
.icon-ai-model:before {
|
||||
content: "\e827";
|
||||
content: '\e827';
|
||||
}
|
||||
|
||||
.icon-ai-model1:before {
|
||||
content: "\ec09";
|
||||
content: '\ec09';
|
||||
}
|
||||
|
||||
.icon-gridlines:before {
|
||||
content: "\e942";
|
||||
content: '\e942';
|
||||
}
|
||||
|
||||
.icon-inbox:before {
|
||||
content: "\e869";
|
||||
content: '\e869';
|
||||
}
|
||||
|
||||
.icon-business-smart-assistant:before {
|
||||
content: "\e601";
|
||||
content: '\e601';
|
||||
}
|
||||
|
||||
.icon-copy:before {
|
||||
content: "\e6ae";
|
||||
content: '\e6ae';
|
||||
}
|
||||
|
||||
.icon-ic_send:before {
|
||||
content: "\e795";
|
||||
content: '\e795';
|
||||
}
|
||||
|
||||
.icon-dark1:before {
|
||||
content: "\e72f";
|
||||
content: '\e72f';
|
||||
}
|
||||
|
||||
.icon-theme-light:before {
|
||||
content: "\e6b7";
|
||||
content: '\e6b7';
|
||||
}
|
||||
|
||||
.icon-translate_line:before {
|
||||
content: "\e7de";
|
||||
content: '\e7de';
|
||||
}
|
||||
|
||||
.icon-history:before {
|
||||
content: "\e758";
|
||||
content: '\e758';
|
||||
}
|
||||
|
||||
.icon-hide-sidebar:before {
|
||||
content: "\e8eb";
|
||||
content: '\e8eb';
|
||||
}
|
||||
|
||||
.icon-show-sidebar:before {
|
||||
content: "\e944";
|
||||
content: '\e944';
|
||||
}
|
||||
|
||||
.icon-appstore:before {
|
||||
content: "\e792";
|
||||
content: '\e792';
|
||||
}
|
||||
|
||||
.icon-chat:before {
|
||||
content: "\e615";
|
||||
content: '\e615';
|
||||
}
|
||||
|
||||
.icon-setting:before {
|
||||
content: "\e78e";
|
||||
content: '\e78e';
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
24
src/renderer/src/components/Icons/ReasoningIcon.tsx
Normal file
24
src/renderer/src/components/Icons/ReasoningIcon.tsx
Normal file
@ -0,0 +1,24 @@
|
||||
import React, { FC } from 'react'
|
||||
import styled from 'styled-components'
|
||||
|
||||
const ReasoningIcon: FC<React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>> = (props) => {
|
||||
return (
|
||||
<Container>
|
||||
<Icon className="iconfont icon-thinking" {...(props as any)} />
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
const Container = styled.div`
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
`
|
||||
|
||||
const Icon = styled.i`
|
||||
color: var(--color-link);
|
||||
font-size: 16px;
|
||||
margin-right: 6px;
|
||||
`
|
||||
|
||||
export default ReasoningIcon
|
||||
@ -1,15 +1,25 @@
|
||||
import { EyeOutlined } from '@ant-design/icons'
|
||||
import { PictureOutlined } 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)} />
|
||||
return (
|
||||
<Container>
|
||||
<Icon {...(props as any)} />
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
const Icon = styled(EyeOutlined)`
|
||||
const Container = styled.div`
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
`
|
||||
|
||||
const Icon = styled(PictureOutlined)`
|
||||
color: var(--color-primary);
|
||||
font-size: 14px;
|
||||
margin-left: 4px;
|
||||
font-size: 15px;
|
||||
margin-right: 6px;
|
||||
`
|
||||
|
||||
export default VisionIcon
|
||||
|
||||
@ -3,13 +3,23 @@ import React, { FC } from 'react'
|
||||
import styled from 'styled-components'
|
||||
|
||||
const WebSearchIcon: FC<React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>> = (props) => {
|
||||
return <Icon {...(props as any)} />
|
||||
return (
|
||||
<Container>
|
||||
<Icon {...(props as any)} />
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
const Container = styled.div`
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
`
|
||||
|
||||
const Icon = styled(GlobalOutlined)`
|
||||
color: var(--color-link);
|
||||
font-size: 12px;
|
||||
margin-left: 4px;
|
||||
font-size: 15px;
|
||||
margin-right: 6px;
|
||||
`
|
||||
|
||||
export default WebSearchIcon
|
||||
|
||||
@ -4,38 +4,37 @@ import { isFreeModel } from '@renderer/utils'
|
||||
import { Tag } from 'antd'
|
||||
import { FC } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import styled from 'styled-components'
|
||||
|
||||
import ReasoningIcon from './Icons/ReasoningIcon'
|
||||
import VisionIcon from './Icons/VisionIcon'
|
||||
import WebSearchIcon from './Icons/WebSearchIcon'
|
||||
|
||||
interface ModelTagsProps {
|
||||
model: Model
|
||||
showFree?: boolean
|
||||
showReasoning?: boolean
|
||||
}
|
||||
|
||||
const ModelTags: FC<ModelTagsProps> = ({ model, showFree = true }) => {
|
||||
const ModelTags: FC<ModelTagsProps> = ({ model, showFree = true, showReasoning = true }) => {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<>
|
||||
<Container>
|
||||
{isVisionModel(model) && <VisionIcon />}
|
||||
{isWebSearchModel(model) && <WebSearchIcon />}
|
||||
{showFree && isFreeModel(model) && (
|
||||
<Tag style={{ marginLeft: 10 }} color="green">
|
||||
{t('models.free')}
|
||||
</Tag>
|
||||
)}
|
||||
{isEmbeddingModel(model) && (
|
||||
<Tag style={{ marginLeft: 10 }} color="orange">
|
||||
{t('models.embedding')}
|
||||
</Tag>
|
||||
)}
|
||||
{isReasoningModel(model) && (
|
||||
<Tag color="blue" style={{ marginLeft: 10 }}>
|
||||
{t('models.reasoning')}
|
||||
</Tag>
|
||||
)}
|
||||
</>
|
||||
{showReasoning && isReasoningModel(model) && <ReasoningIcon />}
|
||||
{isEmbeddingModel(model) && <Tag color="orange">{t('models.embedding')}</Tag>}
|
||||
{showFree && isFreeModel(model) && <Tag color="green">{t('models.free')}</Tag>}
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
const Container = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 2px;
|
||||
`
|
||||
|
||||
export default ModelTags
|
||||
|
||||
@ -74,9 +74,9 @@ const PopupContainer: React.FC<PopupContainerProps> = ({ model, resolve }) => {
|
||||
key: getModelUniqId(m),
|
||||
label: (
|
||||
<ModelItem>
|
||||
<span>
|
||||
{m?.name} <ModelTags model={m} />
|
||||
</span>
|
||||
<ModelNameRow>
|
||||
<span>{m?.name}</span> <ModelTags model={m} />
|
||||
</ModelNameRow>
|
||||
<PinIcon
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
@ -118,7 +118,9 @@ const PopupContainer: React.FC<PopupContainerProps> = ({ model, resolve }) => {
|
||||
key: getModelUniqId(m) + '_pinned',
|
||||
label: (
|
||||
<ModelItem>
|
||||
{m?.name} <ModelTags model={m} />
|
||||
<ModelNameRow>
|
||||
<span>{m?.name}</span> <ModelTags model={m} />
|
||||
</ModelNameRow>
|
||||
<PinIcon
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
@ -277,6 +279,13 @@ const ModelItem = styled.div`
|
||||
width: 100%;
|
||||
`
|
||||
|
||||
const ModelNameRow = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
`
|
||||
|
||||
const EmptyState = styled.div`
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
@ -629,12 +629,12 @@
|
||||
"reasoning": "推論"
|
||||
},
|
||||
"all": "すべて",
|
||||
"vision": "画像モデル",
|
||||
"websearch": "ウェブ検索モデル",
|
||||
"free": "無料モデル",
|
||||
"reasoning": "推論モデル",
|
||||
"embedding": "埋め込みモデル",
|
||||
"embedding_model": "埋め込みモデル",
|
||||
"vision": "画像",
|
||||
"websearch": "ウェブ検索",
|
||||
"free": "無料",
|
||||
"reasoning": "推論",
|
||||
"embedding": "埋め込み",
|
||||
"embedding_model": "埋め込み模型",
|
||||
"embedding_model_tooltip": "設定->モデルサービス->管理で追加",
|
||||
"dimensions": "{{dimensions}} 次元",
|
||||
"custom_parameters": "カスタムパラメータ",
|
||||
|
||||
@ -641,11 +641,11 @@
|
||||
"reasoning": "Рассуждение"
|
||||
},
|
||||
"all": "Все",
|
||||
"vision": "Визуальные модели",
|
||||
"websearch": "Веб-поисковые модели",
|
||||
"free": "Бесплатные модели",
|
||||
"reasoning": "Модели рассуждения",
|
||||
"embedding": "Встраиваемые модели",
|
||||
"vision": "Визуальные",
|
||||
"websearch": "Веб-поисковые",
|
||||
"free": "Бесплатные",
|
||||
"reasoning": "Рассуждение",
|
||||
"embedding": "Встраиваемые",
|
||||
"embedding_model": "Встраиваемые модели",
|
||||
"embedding_model_tooltip": "Добавьте в настройки->модель сервиса->управление",
|
||||
"dimensions": "{{dimensions}} мер",
|
||||
|
||||
@ -494,7 +494,7 @@
|
||||
"delete.title": "删除提供商",
|
||||
"docs_check": "查看",
|
||||
"docs_more_details": "获取更多详情",
|
||||
"get_api_key": "获取密钥",
|
||||
"get_api_key": "点击这里获取密钥",
|
||||
"no_models": "请先添加模型再检查 API 连接",
|
||||
"not_checked": "未检查",
|
||||
"remove_duplicate_keys": "移除重复密钥",
|
||||
@ -636,11 +636,11 @@
|
||||
"reasoning": "推理"
|
||||
},
|
||||
"all": "全部",
|
||||
"vision": "视觉模型",
|
||||
"websearch": "联网模型",
|
||||
"free": "免费模型",
|
||||
"reasoning": "推理模型",
|
||||
"embedding": "嵌入模型",
|
||||
"vision": "视觉",
|
||||
"websearch": "联网",
|
||||
"free": "免费",
|
||||
"reasoning": "推理",
|
||||
"embedding": "嵌入",
|
||||
"embedding_model": "嵌入模型",
|
||||
"embedding_model_tooltip": "在设置->模型服务中点击管理按钮添加",
|
||||
"dimensions": "{{dimensions}} 维",
|
||||
|
||||
@ -493,7 +493,7 @@
|
||||
"delete.title": "刪除提供者",
|
||||
"docs_check": "檢查",
|
||||
"docs_more_details": "查看更多細節",
|
||||
"get_api_key": "獲取密鑰",
|
||||
"get_api_key": "點擊這裡獲取密鑰",
|
||||
"no_models": "請先添加模型再檢查 API 連接",
|
||||
"not_checked": "未檢查",
|
||||
"remove_duplicate_keys": "移除重複密鑰",
|
||||
@ -635,11 +635,11 @@
|
||||
"reasoning": "推理"
|
||||
},
|
||||
"all": "全部",
|
||||
"vision": "視覺模型",
|
||||
"websearch": "網路搜索模型",
|
||||
"free": "免費模型",
|
||||
"reasoning": "推理模型",
|
||||
"embedding": "嵌入模型",
|
||||
"vision": "視覺",
|
||||
"websearch": "網路搜索",
|
||||
"free": "免費",
|
||||
"reasoning": "推理",
|
||||
"embedding": "嵌入",
|
||||
"embedding_model": "嵌入模型",
|
||||
"embedding_model_tooltip": "在设置->模型服务中点击管理按钮添加",
|
||||
"dimensions": "{{dimensions}} 維",
|
||||
|
||||
@ -48,9 +48,9 @@ const MentionModelsButton: FC<Props> = ({ onMentionModel: onSelect, ToolbarButto
|
||||
key: getModelUniqId(m),
|
||||
label: (
|
||||
<ModelItem>
|
||||
<span>
|
||||
{m?.name} <ModelTags model={m} />
|
||||
</span>
|
||||
<ModelNameRow>
|
||||
<span>{m?.name}</span> <ModelTags model={m} />
|
||||
</ModelNameRow>
|
||||
{/* <Checkbox checked={selectedModels.some((sm) => sm.id === m.id)} /> */}
|
||||
<PinIcon
|
||||
onClick={(e) => {
|
||||
@ -136,6 +136,13 @@ const ModelItem = styled.div`
|
||||
}
|
||||
`
|
||||
|
||||
const ModelNameRow = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
`
|
||||
|
||||
const PinIcon = styled.span.attrs({ className: 'pin-icon' })<{ $isPinned: boolean }>`
|
||||
margin-left: auto;
|
||||
padding: 0 8px;
|
||||
|
||||
@ -39,7 +39,7 @@ const SelectModelButton: FC<Props> = ({ assistant }) => {
|
||||
<ModelName>
|
||||
{model ? model.name : t('button.select_model')} {providerName ? '| ' + providerName : ''}
|
||||
</ModelName>
|
||||
<ModelTags model={model} showFree={false} />
|
||||
<ModelTags model={model} showFree={false} showReasoning={false} />
|
||||
</ButtonContent>
|
||||
</DropdownButton>
|
||||
)
|
||||
|
||||
@ -237,6 +237,10 @@ const ListItemHeader = styled.div`
|
||||
`
|
||||
|
||||
const ListItemName = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
color: var(--color-text);
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
@ -252,7 +256,6 @@ const ModelHeaderTitle = styled.div`
|
||||
|
||||
const Question = styled(QuestionCircleOutlined)`
|
||||
cursor: pointer;
|
||||
margin: 0 10px;
|
||||
color: #888;
|
||||
`
|
||||
|
||||
|
||||
@ -309,8 +309,10 @@ const ProviderSetting: FC<Props> = ({ provider: _provider }) => {
|
||||
<Avatar src={getModelLogo(model.id)} size={22} style={{ marginRight: '8px' }}>
|
||||
{model?.name?.[0]?.toUpperCase()}
|
||||
</Avatar>
|
||||
{model?.name}
|
||||
<ModelNameRow>
|
||||
<span>{model?.name}</span>
|
||||
<ModelTags model={model} />
|
||||
</ModelNameRow>
|
||||
<Popover content={modelTypeContent(model)} title={t('models.type.select')} trigger="click">
|
||||
<SettingIcon />
|
||||
</Popover>
|
||||
@ -360,6 +362,13 @@ const ModelListHeader = styled.div`
|
||||
align-items: center;
|
||||
`
|
||||
|
||||
const ModelNameRow = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
`
|
||||
|
||||
const RemoveIcon = styled(MinusCircleOutlined)`
|
||||
font-size: 18px;
|
||||
margin-left: 10px;
|
||||
@ -369,7 +378,7 @@ const RemoveIcon = styled(MinusCircleOutlined)`
|
||||
`
|
||||
|
||||
const SettingIcon = styled(SettingOutlined)`
|
||||
margin-left: 10px;
|
||||
margin-left: 2px;
|
||||
color: var(--color-text);
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease-in-out;
|
||||
|
||||
@ -30,7 +30,7 @@ const persistedReducer = persistReducer(
|
||||
{
|
||||
key: 'cherry-studio',
|
||||
storage,
|
||||
version: 62,
|
||||
version: 63,
|
||||
blacklist: ['runtime'],
|
||||
migrate
|
||||
},
|
||||
|
||||
@ -906,7 +906,6 @@ const migrateConfig = {
|
||||
state.minapps.enabled.push(mintop)
|
||||
}
|
||||
}
|
||||
removeMiniAppIconsFromState(state)
|
||||
return state
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user