diff --git a/web/src/assets/images/model/bedrock.svg b/web/src/assets/images/model/bedrock.svg new file mode 100644 index 00000000..6a0235af --- /dev/null +++ b/web/src/assets/images/model/bedrock.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/web/src/assets/images/model/dashscope.png b/web/src/assets/images/model/dashscope.png new file mode 100644 index 00000000..c1aff40e Binary files /dev/null and b/web/src/assets/images/model/dashscope.png differ diff --git a/web/src/assets/images/model/gpustack.png b/web/src/assets/images/model/gpustack.png new file mode 100644 index 00000000..b154821d Binary files /dev/null and b/web/src/assets/images/model/gpustack.png differ diff --git a/web/src/assets/images/model/ollama.svg b/web/src/assets/images/model/ollama.svg new file mode 100644 index 00000000..f8482a96 --- /dev/null +++ b/web/src/assets/images/model/ollama.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/web/src/assets/images/model/openai.svg b/web/src/assets/images/model/openai.svg new file mode 100644 index 00000000..70686f9b --- /dev/null +++ b/web/src/assets/images/model/openai.svg @@ -0,0 +1,4 @@ + + + + diff --git a/web/src/assets/images/model/xinference.svg b/web/src/assets/images/model/xinference.svg new file mode 100644 index 00000000..f5c5f75e --- /dev/null +++ b/web/src/assets/images/model/xinference.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/src/views/ModelManagement/List.tsx b/web/src/views/ModelManagement/List.tsx index f1127623..ac85125a 100644 --- a/web/src/views/ModelManagement/List.tsx +++ b/web/src/views/ModelManagement/List.tsx @@ -1,5 +1,5 @@ import { useRef, useState, useEffect, type FC } from 'react'; -import { Button, Space, Row, Col } from 'antd' +import { Button, Flex, Row, Col } from 'antd' import { useTranslation } from 'react-i18next'; import type { ProviderModelItem, KeyConfigModalRef, ModelListDetailRef } from './types' @@ -9,6 +9,7 @@ import PageEmpty from '@/components/Empty/PageEmpty'; import Tag from '@/components/Tag'; import KeyConfigModal from './components/KeyConfigModal' import ModelListDetail from './components/ModelListDetail' +import { getLogoUrl } from './utils' const ModelList: FC<{ query: any }> = ({ query }) => { const { t } = useTranslation(); @@ -46,22 +47,25 @@ const ModelList: FC<{ query: any }> = ({ query }) => { {item.provider[0]} } + bodyClassName="rb:relative rb:pb-[64px]! rb:h-[calc(100%-64px)]!" > - {item.tags.map(tag => {t(`modelNew.${tag}`)})} - - - - - - - - + {item.tags.map(tag => {t(`modelNew.${tag}`)})} +
+ + + + + + + + +
))} diff --git a/web/src/views/ModelManagement/Square.tsx b/web/src/views/ModelManagement/Square.tsx index 7ecd838c..af72700f 100644 --- a/web/src/views/ModelManagement/Square.tsx +++ b/web/src/views/ModelManagement/Square.tsx @@ -1,5 +1,5 @@ import { useRef, useState, useEffect, forwardRef, useImperativeHandle } from 'react'; -import { Button, Space, App, Divider, Flex } from 'antd' +import { Button, Space, App, Divider, Flex, Tooltip } from 'antd' import { UsergroupAddOutlined } from '@ant-design/icons'; import { useTranslation } from 'react-i18next'; @@ -9,6 +9,7 @@ import { getModelPlaza, addModelPlaza } from '@/api/models' import PageEmpty from '@/components/Empty/PageEmpty'; import Tag from '@/components/Tag'; import ModelSquareDetail from './components/ModelSquareDetail' +import { getLogoUrl } from './utils' const ModelSquare = forwardRef void; }>(({ query, handleEdit }, ref) => { const { t } = useTranslation(); @@ -46,7 +47,7 @@ const ModelSquare = forwardRef (
-
{vo.provider}
+
{t(`modelNew.${vo.provider}`)}
@@ -55,27 +56,32 @@ const ModelSquare = forwardRef {t(`modelNew.${item.type}`)}} + avatarUrl={getLogoUrl(item.logo)} avatar={
{item.name[0]}
} + bodyClassName="rb:relative rb:pb-[80px]! rb:h-[calc(100%-64px)]!" > - {t(`modelNew.${item.type}`)} -
{item.description}
- {item.tags.map((tag, tagIndex) => {tag})} - - - {item.add_count} - - {!item.is_official && } - {item.is_added - ? - : - } - - + +
{item.description}
+
+ {item.tags.map((tag, tagIndex) => {tag})} +
+ + + {item.add_count} + + {!item.is_official && } + {item.is_added + ? + : + } + + +
))}
diff --git a/web/src/views/ModelManagement/components/ModelListDetail.tsx b/web/src/views/ModelManagement/components/ModelListDetail.tsx index 48abd953..9d4303f8 100644 --- a/web/src/views/ModelManagement/components/ModelListDetail.tsx +++ b/web/src/views/ModelManagement/components/ModelListDetail.tsx @@ -1,6 +1,6 @@ import { useState, useImperativeHandle, forwardRef, useRef } from 'react'; import { useTranslation } from 'react-i18next'; -import { Button, Switch, Row, Col, Space } from 'antd' +import { Button, Switch, Row, Col, Space, Tooltip } from 'antd' import type { ProviderModelItem, ModelListItem, ModelListDetailRef, MultiKeyConfigModalRef } from '../types'; import RbDrawer from '@/components/RbDrawer'; @@ -9,6 +9,7 @@ import Tag from '@/components/Tag'; import PageEmpty from '@/components/Empty/PageEmpty'; import MultiKeyConfigModal from './MultiKeyConfigModal' import { getModelNewList, updateModelStatus } from '@/api/models' +import { getLogoUrl } from '../utils' interface ModelListDetailProps { refresh?: () => void; @@ -80,21 +81,25 @@ const ModelListDetail = forwardRef(({ {t(`modelNew.${item.type}`)} {item.api_keys.length}{t('modelNew.apiKeyNum')} } - avatarUrl={item.logo} + avatarUrl={getLogoUrl(item.logo)} avatar={
{item.name[0]}
} extra={ handleChange(item)} />} + bodyClassName="rb:relative rb:pb-[64px]! rb:h-[calc(100%-64px)]!" > - -
{item.description}
- - - - - + +
{item.description}
+
+
+ + + + + +
))} diff --git a/web/src/views/ModelManagement/components/ModelSquareDetail.tsx b/web/src/views/ModelManagement/components/ModelSquareDetail.tsx index d7a5f807..844339fb 100644 --- a/web/src/views/ModelManagement/components/ModelSquareDetail.tsx +++ b/web/src/views/ModelManagement/components/ModelSquareDetail.tsx @@ -1,6 +1,6 @@ import { useState, useImperativeHandle, forwardRef } from 'react'; import { useTranslation } from 'react-i18next'; -import { Button, Space, App, Flex } from 'antd' +import { Button, Space, App, Flex, Tooltip, Divider } from 'antd' import { UsergroupAddOutlined } from '@ant-design/icons'; import type { ModelPlaza, ModelPlazaItem, ModelSquareDetailRef } from '../types'; @@ -9,6 +9,7 @@ import { getModelPlaza, addModelPlaza } from '@/api/models' import RbCard from '@/components/RbCard/Card' import Tag from '@/components/Tag'; import PageEmpty from '@/components/Empty/PageEmpty'; +import { getLogoUrl } from '../utils' interface ModelSquareDetailProps { refresh: () => void; @@ -52,42 +53,49 @@ const ModelSquareDetail = forwardRef{model.provider} {t('modelNew.modelList')} ({list.length}{t('modelNew.item')})} + title={<>{t(`modelNew.${model.provider}`)} {t('modelNew.modelList')} ({list.length}{t('modelNew.item')})} open={open} onClose={handleClose} > - {list.length === 0 - ? - :
- {list.map(item => ( - - {item.name[0]} +
+ {list.length === 0 + ? + :
+ {list.map(item => ( + {t(`modelNew.${item.type}`)}} + avatarUrl={getLogoUrl(item.logo)} + avatar={ +
+ {item.name[0]} +
+ } + bodyClassName="rb:relative rb:pb-[80px]! rb:h-[calc(100%-64px)]!" + > + +
{item.description}
+
+ {item.tags.map((tag, tagIndex) => {tag})} +
+ + + {item.add_count} + + {!item.is_official && } + {item.is_added + ? + : + } + +
- } - > - {t(`modelNew.${item.type}`)} -
{item.description}
- {item.tags.map((tag, tagIndex) => {tag})} - - - {item.add_count} - - {!item.is_official && } - {item.is_added - ? - : - } - - -
- ))} -
- } + + ))} +
+ } +
); }); diff --git a/web/src/views/ModelManagement/utils.ts b/web/src/views/ModelManagement/utils.ts new file mode 100644 index 00000000..c753a8b6 --- /dev/null +++ b/web/src/views/ModelManagement/utils.ts @@ -0,0 +1,26 @@ +import bedrockIcon from '@/assets/images/model/bedrock.svg' +import dashscopeIcon from '@/assets/images/model/dashscope.png' +import gpustackIcon from '@/assets/images/model/gpustack.png' +import ollamaIcon from '@/assets/images/model/ollama.svg' +import openaiIcon from '@/assets/images/model/openai.svg' +import xinferenceIcon from '@/assets/images/model/xinference.svg' + +export const ICONS = { + bedrock: bedrockIcon, + dashscope: dashscopeIcon, + gpustack: gpustackIcon, + ollama: ollamaIcon, + openai: openaiIcon, + xinference: xinferenceIcon +} + +export const getLogoUrl = (logo?: string) => { + if (!logo) { + return undefined + } + if (logo.startsWith('http')) { + return logo + } + + return ICONS[logo as keyof typeof ICONS] || undefined +} \ No newline at end of file