feat: add localization text and model type support #378

This commit is contained in:
kangfenmao 2024-11-25 10:22:20 +08:00
parent d377376bae
commit 1e2ebe5232
8 changed files with 73 additions and 16 deletions

View File

@ -1,15 +1,15 @@
:root {
--color-scrollbar-thumb: rgba(255, 255, 255, 0.15);
--color-scrollbar-thumb-hover: rgba(255, 255, 255, 0.2);
--color-scrollbar-thumb-right: rgba(255, 255, 255, 0.25);
--color-scrollbar-thumb-right-hover: rgba(255, 255, 255, 0.35);
--color-scrollbar-thumb-right: rgba(255, 255, 255, 0.18);
--color-scrollbar-thumb-right-hover: rgba(255, 255, 255, 0.25);
}
body[theme-mode='light'] {
--color-scrollbar-thumb: rgba(0, 0, 0, 0.15);
--color-scrollbar-thumb-hover: rgba(0, 0, 0, 0.2);
--color-scrollbar-thumb-right: rgba(0, 0, 0, 0.25);
--color-scrollbar-thumb-right-hover: rgba(0, 0, 0, 0.35);
--color-scrollbar-thumb-right: rgba(0, 0, 0, 0.18);
--color-scrollbar-thumb-right-hover: rgba(0, 0, 0, 0.25);
}
/* 全局初始化滚动条样式 */

View File

@ -145,7 +145,7 @@ const visionAllowedModels = [
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`,
'i'
)
@ -1044,7 +1044,7 @@ export function isEmbeddingModel(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 {

View File

@ -145,7 +145,12 @@
"model": {
"stream_output": "Stream Output",
"search": "Search models...",
"pinned": "Pinned"
"pinned": "Pinned",
"type": {
"text": "Text",
"vision": "Vision",
"select": "Select Model Types"
}
},
"paintings": {
"title": "Images",

View File

@ -145,7 +145,12 @@
"model": {
"stream_output": "Потоковый вывод",
"search": "Поиск моделей...",
"pinned": "Закреплено"
"pinned": "Закреплено",
"type": {
"text": "Текст",
"vision": "Изображение",
"select": "Выберите тип модели"
}
},
"paintings": {
"title": "Изображения",

View File

@ -145,7 +145,12 @@
"model": {
"stream_output": "流式输出",
"search": "搜索模型...",
"pinned": "已固定"
"pinned": "已固定",
"type": {
"text": "文本",
"vision": "图像",
"select": "选择模型类型"
}
},
"paintings": {
"title": "图片",
@ -316,7 +321,7 @@
"about.title": "关于我们",
"about.releases.title": "更新日志",
"about.releases.button": "查看",
"about.website.title": "官方网",
"about.website.title": "官方网<EFBFBD><EFBFBD><EFBFBD>",
"about.website.button": "查看",
"about.feedback.title": "意见反馈",
"about.feedback.button": "反馈",

View File

@ -145,7 +145,12 @@
"model": {
"stream_output": "串流輸出",
"search": "搜尋模型...",
"pinned": "已固定"
"pinned": "已固定",
"type": {
"text": "文字",
"vision": "圖像",
"select": "選擇模型類型"
}
},
"paintings": {
"title": "繪圖",
@ -431,7 +436,7 @@
"user": "用戶",
"assistant": "助手",
"created": "創建時間",
"last_updated": "最後新",
"last_updated": "最後<EFBFBD><EFBFBD>新",
"messages": "訊息數",
"conversation_details": "會話詳情",
"conversation_history": "會話歷史"

View File

@ -4,18 +4,19 @@ import {
ExportOutlined,
LoadingOutlined,
MinusCircleOutlined,
PlusOutlined
PlusOutlined,
SettingOutlined
} from '@ant-design/icons'
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 { useTheme } from '@renderer/context/ThemeProvider'
import { useProvider } from '@renderer/hooks/useProvider'
import i18n from '@renderer/i18n'
import { isOpenAIProvider } from '@renderer/providers/ProviderFactory'
import { checkApi } from '@renderer/services/ApiService'
import { Provider } from '@renderer/types'
import { Avatar, Button, Card, Divider, Flex, Input, Space, Switch } from 'antd'
import { Model, ModelType, Provider } from '@renderer/types'
import { Avatar, Button, Card, Checkbox, Divider, Flex, Input, Popover, Space, Switch } from 'antd'
import Link from 'antd/es/typography/Link'
import { groupBy, isEmpty } from 'lodash'
import { FC, useEffect, useState } from 'react'
@ -125,6 +126,26 @@ const ProviderSetting: FC<Props> = ({ provider: _provider }) => {
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 (
<SettingContainer theme={theme}>
<SettingTitle>
@ -211,6 +232,9 @@ const ProviderSetting: FC<Props> = ({ provider: _provider }) => {
{model.name[0].toUpperCase()}
</Avatar>
{model.name} {isVisionModel(model) && <VisionIcon />}
<Popover content={modelTypeContent(model)} title={t('model.type.select')} trigger="click">
<SettingIcon />
</Popover>
</ModelListHeader>
<RemoveIcon onClick={() => removeModel(model)} />
</ModelListItem>
@ -265,4 +289,14 @@ const RemoveIcon = styled(MinusCircleOutlined)`
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

View File

@ -78,6 +78,8 @@ export type Provider = {
export type ProviderType = 'openai' | 'anthropic' | 'gemini'
export type ModelType = 'text' | 'vision'
export type Model = {
id: string
provider: string
@ -85,6 +87,7 @@ export type Model = {
group: string
owned_by?: string
description?: string
type?: ModelType[]
}
export type Suggestion = {