mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-07 05:39:05 +08:00
feat: add localization text and model type support #378
This commit is contained in:
parent
d377376bae
commit
1e2ebe5232
@ -1,15 +1,15 @@
|
|||||||
:root {
|
:root {
|
||||||
--color-scrollbar-thumb: rgba(255, 255, 255, 0.15);
|
--color-scrollbar-thumb: rgba(255, 255, 255, 0.15);
|
||||||
--color-scrollbar-thumb-hover: rgba(255, 255, 255, 0.2);
|
--color-scrollbar-thumb-hover: rgba(255, 255, 255, 0.2);
|
||||||
--color-scrollbar-thumb-right: rgba(255, 255, 255, 0.25);
|
--color-scrollbar-thumb-right: rgba(255, 255, 255, 0.18);
|
||||||
--color-scrollbar-thumb-right-hover: rgba(255, 255, 255, 0.35);
|
--color-scrollbar-thumb-right-hover: rgba(255, 255, 255, 0.25);
|
||||||
}
|
}
|
||||||
|
|
||||||
body[theme-mode='light'] {
|
body[theme-mode='light'] {
|
||||||
--color-scrollbar-thumb: rgba(0, 0, 0, 0.15);
|
--color-scrollbar-thumb: rgba(0, 0, 0, 0.15);
|
||||||
--color-scrollbar-thumb-hover: rgba(0, 0, 0, 0.2);
|
--color-scrollbar-thumb-hover: rgba(0, 0, 0, 0.2);
|
||||||
--color-scrollbar-thumb-right: rgba(0, 0, 0, 0.25);
|
--color-scrollbar-thumb-right: rgba(0, 0, 0, 0.18);
|
||||||
--color-scrollbar-thumb-right-hover: rgba(0, 0, 0, 0.35);
|
--color-scrollbar-thumb-right-hover: rgba(0, 0, 0, 0.25);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 全局初始化滚动条样式 */
|
/* 全局初始化滚动条样式 */
|
||||||
|
|||||||
@ -145,7 +145,7 @@ const visionAllowedModels = [
|
|||||||
|
|
||||||
const visionExcludedModels = ['gpt-4-\\d+-preview', 'gpt-4-turbo-preview', 'gpt-4-32k', 'gpt-4-\\d+']
|
const visionExcludedModels = ['gpt-4-\\d+-preview', 'gpt-4-turbo-preview', 'gpt-4-32k', 'gpt-4-\\d+']
|
||||||
|
|
||||||
const VISION_REGEX = new RegExp(
|
export const VISION_REGEX = new RegExp(
|
||||||
`\\b(?!(?:${visionExcludedModels.join('|')})\\b)(${visionAllowedModels.join('|')})\\b`,
|
`\\b(?!(?:${visionExcludedModels.join('|')})\\b)(${visionAllowedModels.join('|')})\\b`,
|
||||||
'i'
|
'i'
|
||||||
)
|
)
|
||||||
@ -1044,7 +1044,7 @@ export function isEmbeddingModel(model: Model): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function isVisionModel(model: Model): boolean {
|
export function isVisionModel(model: Model): boolean {
|
||||||
return VISION_REGEX.test(model.id)
|
return VISION_REGEX.test(model.id) || model.type?.includes('vision') || false
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isSupportedModel(model: OpenAI.Models.Model): boolean {
|
export function isSupportedModel(model: OpenAI.Models.Model): boolean {
|
||||||
|
|||||||
@ -145,7 +145,12 @@
|
|||||||
"model": {
|
"model": {
|
||||||
"stream_output": "Stream Output",
|
"stream_output": "Stream Output",
|
||||||
"search": "Search models...",
|
"search": "Search models...",
|
||||||
"pinned": "Pinned"
|
"pinned": "Pinned",
|
||||||
|
"type": {
|
||||||
|
"text": "Text",
|
||||||
|
"vision": "Vision",
|
||||||
|
"select": "Select Model Types"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"paintings": {
|
"paintings": {
|
||||||
"title": "Images",
|
"title": "Images",
|
||||||
|
|||||||
@ -145,7 +145,12 @@
|
|||||||
"model": {
|
"model": {
|
||||||
"stream_output": "Потоковый вывод",
|
"stream_output": "Потоковый вывод",
|
||||||
"search": "Поиск моделей...",
|
"search": "Поиск моделей...",
|
||||||
"pinned": "Закреплено"
|
"pinned": "Закреплено",
|
||||||
|
"type": {
|
||||||
|
"text": "Текст",
|
||||||
|
"vision": "Изображение",
|
||||||
|
"select": "Выберите тип модели"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"paintings": {
|
"paintings": {
|
||||||
"title": "Изображения",
|
"title": "Изображения",
|
||||||
|
|||||||
@ -145,7 +145,12 @@
|
|||||||
"model": {
|
"model": {
|
||||||
"stream_output": "流式输出",
|
"stream_output": "流式输出",
|
||||||
"search": "搜索模型...",
|
"search": "搜索模型...",
|
||||||
"pinned": "已固定"
|
"pinned": "已固定",
|
||||||
|
"type": {
|
||||||
|
"text": "文本",
|
||||||
|
"vision": "图像",
|
||||||
|
"select": "选择模型类型"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"paintings": {
|
"paintings": {
|
||||||
"title": "图片",
|
"title": "图片",
|
||||||
@ -316,7 +321,7 @@
|
|||||||
"about.title": "关于我们",
|
"about.title": "关于我们",
|
||||||
"about.releases.title": "更新日志",
|
"about.releases.title": "更新日志",
|
||||||
"about.releases.button": "查看",
|
"about.releases.button": "查看",
|
||||||
"about.website.title": "官方网站",
|
"about.website.title": "官方网<EFBFBD><EFBFBD><EFBFBD>",
|
||||||
"about.website.button": "查看",
|
"about.website.button": "查看",
|
||||||
"about.feedback.title": "意见反馈",
|
"about.feedback.title": "意见反馈",
|
||||||
"about.feedback.button": "反馈",
|
"about.feedback.button": "反馈",
|
||||||
|
|||||||
@ -145,7 +145,12 @@
|
|||||||
"model": {
|
"model": {
|
||||||
"stream_output": "串流輸出",
|
"stream_output": "串流輸出",
|
||||||
"search": "搜尋模型...",
|
"search": "搜尋模型...",
|
||||||
"pinned": "已固定"
|
"pinned": "已固定",
|
||||||
|
"type": {
|
||||||
|
"text": "文字",
|
||||||
|
"vision": "圖像",
|
||||||
|
"select": "選擇模型類型"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"paintings": {
|
"paintings": {
|
||||||
"title": "繪圖",
|
"title": "繪圖",
|
||||||
@ -431,7 +436,7 @@
|
|||||||
"user": "用戶",
|
"user": "用戶",
|
||||||
"assistant": "助手",
|
"assistant": "助手",
|
||||||
"created": "創建時間",
|
"created": "創建時間",
|
||||||
"last_updated": "最後更新",
|
"last_updated": "最後<EFBFBD><EFBFBD>新",
|
||||||
"messages": "訊息數",
|
"messages": "訊息數",
|
||||||
"conversation_details": "會話詳情",
|
"conversation_details": "會話詳情",
|
||||||
"conversation_history": "會話歷史"
|
"conversation_history": "會話歷史"
|
||||||
|
|||||||
@ -4,18 +4,19 @@ import {
|
|||||||
ExportOutlined,
|
ExportOutlined,
|
||||||
LoadingOutlined,
|
LoadingOutlined,
|
||||||
MinusCircleOutlined,
|
MinusCircleOutlined,
|
||||||
PlusOutlined
|
PlusOutlined,
|
||||||
|
SettingOutlined
|
||||||
} from '@ant-design/icons'
|
} from '@ant-design/icons'
|
||||||
import VisionIcon from '@renderer/components/Icons/VisionIcon'
|
import VisionIcon from '@renderer/components/Icons/VisionIcon'
|
||||||
import { getModelLogo, isVisionModel } from '@renderer/config/models'
|
import { getModelLogo, isVisionModel, VISION_REGEX } from '@renderer/config/models'
|
||||||
import { PROVIDER_CONFIG } from '@renderer/config/providers'
|
import { PROVIDER_CONFIG } from '@renderer/config/providers'
|
||||||
import { useTheme } from '@renderer/context/ThemeProvider'
|
import { useTheme } from '@renderer/context/ThemeProvider'
|
||||||
import { useProvider } from '@renderer/hooks/useProvider'
|
import { useProvider } from '@renderer/hooks/useProvider'
|
||||||
import i18n from '@renderer/i18n'
|
import i18n from '@renderer/i18n'
|
||||||
import { isOpenAIProvider } from '@renderer/providers/ProviderFactory'
|
import { isOpenAIProvider } from '@renderer/providers/ProviderFactory'
|
||||||
import { checkApi } from '@renderer/services/ApiService'
|
import { checkApi } from '@renderer/services/ApiService'
|
||||||
import { Provider } from '@renderer/types'
|
import { Model, ModelType, Provider } from '@renderer/types'
|
||||||
import { Avatar, Button, Card, Divider, Flex, Input, Space, Switch } from 'antd'
|
import { Avatar, Button, Card, Checkbox, Divider, Flex, Input, Popover, Space, Switch } from 'antd'
|
||||||
import Link from 'antd/es/typography/Link'
|
import Link from 'antd/es/typography/Link'
|
||||||
import { groupBy, isEmpty } from 'lodash'
|
import { groupBy, isEmpty } from 'lodash'
|
||||||
import { FC, useEffect, useState } from 'react'
|
import { FC, useEffect, useState } from 'react'
|
||||||
@ -125,6 +126,26 @@ const ProviderSetting: FC<Props> = ({ provider: _provider }) => {
|
|||||||
return (apiHost.endsWith('/') ? apiHost : `${apiHost}/v1/`) + 'chat/completions'
|
return (apiHost.endsWith('/') ? apiHost : `${apiHost}/v1/`) + 'chat/completions'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onUpdateModelTypes = (model: Model, types: ModelType[]) => {
|
||||||
|
const updatedModels = models.map((m) => {
|
||||||
|
if (m.id === model.id) {
|
||||||
|
return { ...m, type: types }
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
})
|
||||||
|
updateProvider({ ...provider, models: updatedModels })
|
||||||
|
}
|
||||||
|
|
||||||
|
const modelTypeContent = (model: Model) => (
|
||||||
|
<div>
|
||||||
|
<Checkbox.Group
|
||||||
|
value={model.type}
|
||||||
|
onChange={(types) => onUpdateModelTypes(model, types as ModelType[])}
|
||||||
|
options={[{ label: t('model.type.vision'), value: 'vision', disabled: VISION_REGEX.test(model.id) }]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingContainer theme={theme}>
|
<SettingContainer theme={theme}>
|
||||||
<SettingTitle>
|
<SettingTitle>
|
||||||
@ -211,6 +232,9 @@ const ProviderSetting: FC<Props> = ({ provider: _provider }) => {
|
|||||||
{model.name[0].toUpperCase()}
|
{model.name[0].toUpperCase()}
|
||||||
</Avatar>
|
</Avatar>
|
||||||
{model.name} {isVisionModel(model) && <VisionIcon />}
|
{model.name} {isVisionModel(model) && <VisionIcon />}
|
||||||
|
<Popover content={modelTypeContent(model)} title={t('model.type.select')} trigger="click">
|
||||||
|
<SettingIcon />
|
||||||
|
</Popover>
|
||||||
</ModelListHeader>
|
</ModelListHeader>
|
||||||
<RemoveIcon onClick={() => removeModel(model)} />
|
<RemoveIcon onClick={() => removeModel(model)} />
|
||||||
</ModelListItem>
|
</ModelListItem>
|
||||||
@ -265,4 +289,14 @@ const RemoveIcon = styled(MinusCircleOutlined)`
|
|||||||
transition: all 0.2s ease-in-out;
|
transition: all 0.2s ease-in-out;
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const SettingIcon = styled(SettingOutlined)`
|
||||||
|
margin-left: 10px;
|
||||||
|
color: var(--color-text);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease-in-out;
|
||||||
|
&:hover {
|
||||||
|
color: var(--color-text-2);
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
export default ProviderSetting
|
export default ProviderSetting
|
||||||
|
|||||||
@ -78,6 +78,8 @@ export type Provider = {
|
|||||||
|
|
||||||
export type ProviderType = 'openai' | 'anthropic' | 'gemini'
|
export type ProviderType = 'openai' | 'anthropic' | 'gemini'
|
||||||
|
|
||||||
|
export type ModelType = 'text' | 'vision'
|
||||||
|
|
||||||
export type Model = {
|
export type Model = {
|
||||||
id: string
|
id: string
|
||||||
provider: string
|
provider: string
|
||||||
@ -85,6 +87,7 @@ export type Model = {
|
|||||||
group: string
|
group: string
|
||||||
owned_by?: string
|
owned_by?: string
|
||||||
description?: string
|
description?: string
|
||||||
|
type?: ModelType[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Suggestion = {
|
export type Suggestion = {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user