From a5c1b8e15f07c1d6997b74842d813446b19a6952 Mon Sep 17 00:00:00 2001 From: jialin Date: Sun, 28 Sep 2025 20:32:17 +0800 Subject: [PATCH] chore: test by api --- src/components/icon-font/index.tsx | 2 +- src/components/templates/card.tsx | 2 +- src/locales/en-US/backends.ts | 3 + src/locales/ja-JP/backends.ts | 3 + src/locales/ru-RU/backends.ts | 3 + src/locales/zh-CN/backends.ts | 3 + .../_components/collapse-panel/index.tsx | 13 +- src/pages/api-keys/index.tsx | 12 +- src/pages/backends/apis/index.ts | 2 +- src/pages/backends/components/add-modal.tsx | 84 +++++++++- .../backends/components/backend-card.tsx | 143 ++++++++++++++---- .../backends/components/backend-list.tsx | 10 +- src/pages/backends/components/import-yaml.tsx | 10 +- src/pages/backends/components/yaml-editor.tsx | 21 ++- src/pages/backends/config/index.ts | 114 ++++++++++---- .../{schema.json => schema/create.json} | 31 ++-- .../config/schema/update-builtin.json | 48 ++++++ .../backends/config/schema/update-custom.json | 52 +++++++ src/pages/backends/config/test.ts | 54 ------- src/pages/backends/config/types.ts | 17 ++- src/pages/backends/forms/basic.tsx | 41 ++--- src/pages/backends/forms/index.tsx | 37 ++++- src/pages/backends/forms/versions-config.tsx | 92 ++++++----- src/pages/backends/hooks/use-export-yaml.ts | 14 ++ src/pages/backends/list.tsx | 95 ++++++++++-- src/pages/llmodels/apis/index.ts | 62 ++------ src/pages/llmodels/components/table-list.tsx | 6 +- src/pages/users/index.tsx | 6 + typings.d.ts | 1 + 29 files changed, 683 insertions(+), 298 deletions(-) create mode 100644 src/locales/en-US/backends.ts create mode 100644 src/locales/ja-JP/backends.ts create mode 100644 src/locales/ru-RU/backends.ts create mode 100644 src/locales/zh-CN/backends.ts rename src/pages/backends/config/{schema.json => schema/create.json} (65%) create mode 100644 src/pages/backends/config/schema/update-builtin.json create mode 100644 src/pages/backends/config/schema/update-custom.json delete mode 100644 src/pages/backends/config/test.ts create mode 100644 src/pages/backends/hooks/use-export-yaml.ts diff --git a/src/components/icon-font/index.tsx b/src/components/icon-font/index.tsx index 9ed10a53..d31ea97a 100644 --- a/src/components/icon-font/index.tsx +++ b/src/components/icon-font/index.tsx @@ -2,7 +2,7 @@ import { createFromIconfontCN } from '@ant-design/icons'; // import './iconfont/iconfont.js'; const IconFont = createFromIconfontCN({ - scriptUrl: '//at.alicdn.com/t/c/font_4613488_c06q7b0n32v.js' + scriptUrl: '//at.alicdn.com/t/c/font_4613488_gacm1yqzw1w.js' }); export default IconFont; diff --git a/src/components/templates/card.tsx b/src/components/templates/card.tsx index dba395eb..d4b22e04 100644 --- a/src/components/templates/card.tsx +++ b/src/components/templates/card.tsx @@ -21,7 +21,7 @@ const CardWrapper = styled.div.attrs({ })` overflow: hidden; display: flex; - padding: 22px; + padding: 16px 20px; justify-content: flex-start; align-items: center; border: 1px solid var(--ant-color-border); diff --git a/src/locales/en-US/backends.ts b/src/locales/en-US/backends.ts new file mode 100644 index 00000000..2ab5048c --- /dev/null +++ b/src/locales/en-US/backends.ts @@ -0,0 +1,3 @@ +export default { + 'backends.title': 'Backends' +}; diff --git a/src/locales/ja-JP/backends.ts b/src/locales/ja-JP/backends.ts new file mode 100644 index 00000000..2ab5048c --- /dev/null +++ b/src/locales/ja-JP/backends.ts @@ -0,0 +1,3 @@ +export default { + 'backends.title': 'Backends' +}; diff --git a/src/locales/ru-RU/backends.ts b/src/locales/ru-RU/backends.ts new file mode 100644 index 00000000..2ab5048c --- /dev/null +++ b/src/locales/ru-RU/backends.ts @@ -0,0 +1,3 @@ +export default { + 'backends.title': 'Backends' +}; diff --git a/src/locales/zh-CN/backends.ts b/src/locales/zh-CN/backends.ts new file mode 100644 index 00000000..14a6b7b9 --- /dev/null +++ b/src/locales/zh-CN/backends.ts @@ -0,0 +1,3 @@ +export default { + 'backends.title': '后端' +}; diff --git a/src/pages/_components/collapse-panel/index.tsx b/src/pages/_components/collapse-panel/index.tsx index 94618082..e572b14a 100644 --- a/src/pages/_components/collapse-panel/index.tsx +++ b/src/pages/_components/collapse-panel/index.tsx @@ -30,15 +30,20 @@ const CollapseInner = styled(Collapse)` } `; -const CollapsePanel: React.FC<{ items: CollapseProps['items'] }> = ({ - items -}) => { +const CollapsePanel: React.FC<{ + items: CollapseProps['items']; + activeKey: string | string[]; + accordion?: boolean; + onChange?: (key: string | string[]) => void; +}> = ({ items, activeKey, accordion, onChange }) => { return ( ( { left={ + } placeholder={intl.formatMessage({ id: 'common.filter.name' })} style={{ width: 300 }} allowClear diff --git a/src/pages/backends/apis/index.ts b/src/pages/backends/apis/index.ts index 6b27cbd8..56a4d5af 100644 --- a/src/pages/backends/apis/index.ts +++ b/src/pages/backends/apis/index.ts @@ -1,7 +1,7 @@ import { request } from '@umijs/max'; import { FormData, ListItem } from '../config/types'; -export const INFERENCE_BACKEND_API = '/inference-backend'; +export const INFERENCE_BACKEND_API = '/inference-backends'; export const FROM_YAML_API = '/from-yaml'; diff --git a/src/pages/backends/components/add-modal.tsx b/src/pages/backends/components/add-modal.tsx index 4acbc7b6..442c6bb9 100644 --- a/src/pages/backends/components/add-modal.tsx +++ b/src/pages/backends/components/add-modal.tsx @@ -1,12 +1,15 @@ import IconFont from '@/components/icon-font'; import ModalFooter from '@/components/modal-footer'; import GSDrawer from '@/components/scroller-modal/gs-drawer'; +import { PageAction } from '@/config'; import { PageActionType } from '@/config/types'; import { useIntl } from '@umijs/max'; import { Segmented, Tabs } from 'antd'; -import React, { useRef, useState } from 'react'; +import _ from 'lodash'; +import React, { useEffect, useRef, useState } from 'react'; import styled from 'styled-components'; import ColumnWrapper from '../../_components/column-wrapper'; +import { backendFields, json2Yaml } from '../config'; import { FormData, ListItem } from '../config/types'; import BackendForm from '../forms'; import ImportYAML from './import-yaml'; @@ -35,23 +38,28 @@ interface AddModalProps { currentData?: ListItem; // Used when action is EDIT onClose: () => void; onSubmit: (values: FormData) => void; + onSubmitYaml: (values: { content: string }) => void; open: boolean; title?: string; } const AddModal: React.FC = (props) => { - const { action, currentData, onClose, onSubmit, open, title } = props; + const { action, currentData, onClose, onSubmit, onSubmitYaml, open, title } = + props; const formRef = useRef(null); const editorRef = useRef(null); const intl = useIntl(); const [activeKey, setActiveKey] = useState('form'); + const [yamlContent, setYamlContent] = useState(''); + const [formContent, setFormContent] = useState({} as FormData); + const tabsRef = useRef(null); const onOk = () => { if (activeKey === 'yaml') { const content = editorRef.current?.getContent(); const valid = editorRef.current?.validate(); if (valid) { - onSubmit({ content: content }); + onSubmitYaml({ content: content }); } } else { formRef.current?.submit(); @@ -59,9 +67,64 @@ const AddModal: React.FC = (props) => { }; const onFinish = (values: FormData) => { - onSubmit(values); + console.log('Form values:', values); + const versionConfigs = values.version_configs?.reduce( + (acc: Record, curr) => { + if (curr.version_no) { + acc[curr.version_no] = { + image_name: curr.image_name, + run_command: curr.run_command + }; + } + return acc; + }, + {} + ); + + const defaultVersion = values.version_configs?.find((v) => v.is_default); + + onSubmit({ + ...values, + default_version: defaultVersion?.version_no || '', + // @ts-ignore + version_configs: versionConfigs + }); }; + const iniFormContent = (values: any) => { + const versionConfigs = Object.keys(values.version_configs || {}).map( + (key) => ({ + version_no: key, + image_name: values.version_configs[key].image_name, + run_command: values.version_configs[key].run_command, + is_default: key === values.default_version, + isBuiltin: true + }) + ); + return { + ...values, + version_configs: versionConfigs + }; + }; + + const initYamlContent = (values: any) => { + if (currentData?.is_build_in) { + return json2Yaml(_.pick(values, backendFields)); + } + return json2Yaml(_.pick(values, [...backendFields, 'default_version'])); + }; + + useEffect(() => { + if (action === PageAction.EDIT) { + const yaml = initYamlContent(currentData || {}); + const formData = iniFormContent(currentData || {}); + setYamlContent(yaml); + setFormContent(formData); + formRef.current?.setFieldsValue?.(formData); + editorRef.current?.setValue?.(yaml); + } + }, [action, currentData]); + return ( = (props) => { } > <>} + renderTabBar={(agrs, tab) => <>} activeKey={activeKey} defaultActiveKey={activeKey} items={[ @@ -126,7 +189,7 @@ const AddModal: React.FC = (props) => { ) @@ -135,7 +198,14 @@ const AddModal: React.FC = (props) => { key: 'yaml', label: 'YAML', children: ( - + ) } ]} diff --git a/src/pages/backends/components/backend-card.tsx b/src/pages/backends/components/backend-card.tsx index edf53377..82605430 100644 --- a/src/pages/backends/components/backend-card.tsx +++ b/src/pages/backends/components/backend-card.tsx @@ -1,12 +1,30 @@ import DropDownActions from '@/components/drop-down-actions'; import IconFont from '@/components/icon-font'; import Card from '@/components/templates/card'; -import { DockerOutlined } from '@ant-design/icons'; -import { Button } from 'antd'; +import { DockerOutlined, InfoCircleOutlined } from '@ant-design/icons'; +import { Button, Tag } from 'antd'; +import _ from 'lodash'; +import { useMemo } from 'react'; import styled from 'styled-components'; -import { backendActions } from '../config'; +import { + backendActions, + builtInBackendLogos, + customColors, + customIcons +} from '../config'; import { ListItem } from '../config/types'; +const TagInner = styled(Tag)` + display: flex; + align-items: center; + justify-content: center; + font-size: 18px; + height: 28px; + width: 28px; + border-radius: 6px; + font-weight: 400; +`; + const Header = styled.div` display: flex; align-items: center; @@ -15,16 +33,26 @@ const Header = styled.div` .title { display: flex; align-items: center; - gap: 16px; + gap: 24px; } `; +const CardName = styled.div` + font-weight: 500; + font-size: 16px; + display: flex; + align-items: center; + color: var(--ant-color-text); + margin-bottom: 4px; + gap: 16px; +`; + const Content = styled.div` display: flex; flex-direction: column; align-items: flex-start; - margin-top: 8px; - gap: 12px; + margin-top: 12px; + gap: 16px; color: var(--ant-color-text-secondary); .description { margin-block: 12px; @@ -32,44 +60,81 @@ const Content = styled.div` } .text { margin-left: 4px; - color: var(--ant-color-text-secondary); + color: var(--ant-color-text); } .title { color: var(--ant-color-text); font-weight: 500; line-height: 1.5; } + .info { + display: grid; + grid-template-columns: max-content 1fr; + align-items: center; + gap: 8px; + color: var(--ant-color-text-tertiary); + .icon { + color: var(--ant-color-text-tertiary); + } + .label { + display: flex; + align-items: center; + gap: 4px; + } + } `; interface BackendCardProps { - onClick: (data: any) => void; + onClick?: (data: any) => void; onSelect?: (item: any) => void; data: ListItem; } -const BackendCard: React.FC = ({ - onClick, - data, - onSelect -}) => { +const BackendCard: React.FC = ({ data, onSelect }) => { + const handleOnSelect = (item: any) => { + onSelect?.({ action: item.key, data: data }); + }; + + const handleClick = () => { + onSelect?.({ action: 'edit', data: data }); + }; + + const renderIcon = () => { + if (builtInBackendLogos[data.backend_name]) { + return ; + } + const color = customColors[data.id % customColors.length]; + const icon = customIcons[data.id % customIcons.length]; + + return ( + + {icon} + + ); + }; + + const actions = useMemo(() => { + if (data.is_build_in) { + return backendActions.filter((item) => item.key !== 'delete'); + } + return backendActions; + }, [data.is_build_in]); + return ( onClick(data)} + onClick={handleClick} clickable={true} disabled={false} - height={'auto'} + height={160} ghost header={
-
- {data.backend_name} - {data.backend_name} -
+
{renderIcon()}
+ + handleSetDefaultVersion(e, index) + } + > + Set as Default Version + + )} - + + { +
+ {fields.length > 1 && ( + + )} +
+ } { + const exportYAML = (currentData?: any) => { + const yaml = json2Yaml(currentData || {}); + const blob = new Blob([yaml], { type: 'text/yaml;charset=utf-8' }); + downloadFile(blob, `${currentData.backend_name}.yml`); + }; + + return { exportYAML }; +}; + +export default useExportYAML; diff --git a/src/pages/backends/list.tsx b/src/pages/backends/list.tsx index 878473d3..cfc3d5e1 100644 --- a/src/pages/backends/list.tsx +++ b/src/pages/backends/list.tsx @@ -1,3 +1,4 @@ +import DeleteModal from '@/components/delete-modal'; import { FilterBar } from '@/components/page-tools'; import { PageActionType } from '@/config/types'; import useTableFetch from '@/hooks/use-table-fetch'; @@ -5,14 +6,19 @@ import { PageContainer } from '@ant-design/pro-components'; import { useIntl } from '@umijs/max'; import { useState } from 'react'; import { + createBackend, + createBackendFromYAML, deleteBackend, INFERENCE_BACKEND_API, - queryBackendsList + queryBackendsList, + updateBackend, + updateBackendFromYAML } from './apis'; import AddModal from './components/add-modal'; import BackendCardList from './components/backend-list'; -import dataList from './config/test'; +import { json2Yaml, yaml2Json } from './config'; import { FormData, ListItem } from './config/types'; +import useExportYAML from './hooks/use-export-yaml'; const BackendList = () => { const intl = useIntl(); @@ -35,21 +41,62 @@ const BackendList = () => { deleteAPI: deleteBackend, API: INFERENCE_BACKEND_API, watch: false, - contentForDelete: 'resources.modelfiles.modelfile' + contentForDelete: 'backends.title', + defaultQueryParams: { + perPage: 100 + } }); + const { exportYAML } = useExportYAML(); const [openModalStatus, setOpenModalStatus] = useState<{ open: boolean; action: PageActionType; - currentData?: Partial; + currentData?: Partial; }>({ open: false, action: 'create' }); - const handleOnSubmit = (values: FormData) => { - console.log('yaml content:', values); - setOpenModalStatus({ - open: false, - action: 'create', - currentData: undefined - }); + const handleOnSubmit = async (values: FormData) => { + try { + if (openModalStatus.action === 'create') { + await createBackend({ data: values }); + } else { + await updateBackend(openModalStatus.currentData!.id!, { + data: { + ...values + } + }); + } + setOpenModalStatus({ + open: false, + action: 'create', + currentData: undefined + }); + handleSearch(); + } catch (error) {} + }; + + const handleOnSubmitYaml = async (values: { content: string }) => { + try { + if (openModalStatus.action === 'create') { + await createBackendFromYAML({ data: values }); + } else { + const jsonData = yaml2Json(values.content); + const yamlContent = json2Yaml({ + backend_name: openModalStatus.currentData?.backend_name, + default_version: openModalStatus.currentData?.default_version, + ...jsonData + }); + await updateBackendFromYAML(openModalStatus.currentData!.id!, { + data: { + content: yamlContent + } + }); + } + setOpenModalStatus({ + open: false, + action: 'create', + currentData: undefined + }); + handleSearch(); + } catch (error) {} }; const handleAddBackend = () => { @@ -59,6 +106,25 @@ const BackendList = () => { }); }; + const handleOnSelect = (item: any) => { + console.log('selected item:', item); + if (item.action === 'edit') { + setOpenModalStatus({ + open: true, + action: 'edit', + currentData: item.data + }); + } else if (item.action === 'delete') { + handleDelete(item.data, { + name: item.data.backend_name + }); + } else if (item.action === 'export') { + // Export YAML action + console.log('Export YAML for:', item.data); + exportYAML(item.data); + } + }; + return ( { > setOpenModalStatus({ open: false, action: 'create' })} onSubmit={handleOnSubmit} - currentData={openModalStatus.currentData} + onSubmitYaml={handleOnSubmitYaml} + currentData={openModalStatus.currentData as ListItem} open={openModalStatus.open} title={ openModalStatus.action === 'create' @@ -105,6 +173,7 @@ const BackendList = () => { : 'Edit Backend' } > + ); }; diff --git a/src/pages/llmodels/apis/index.ts b/src/pages/llmodels/apis/index.ts index 2dc86d69..cf3f5af9 100644 --- a/src/pages/llmodels/apis/index.ts +++ b/src/pages/llmodels/apis/index.ts @@ -20,7 +20,7 @@ export const MODEL_INSTANCE_API = '/model-instances'; export const MODEL_EVALUATIONS = '/model-evaluations'; -export const BACKEND_LIST_API = '/inference-backend/list'; +export const BACKEND_LIST_API = '/inference-backends/list'; const setProxyUrl = (url: string) => { return `/proxy?url=${encodeURIComponent(url)}`; @@ -400,52 +400,16 @@ export async function evaluationsModelSpec( } export async function queryBackendList() { - // return request<{ - // items: { - // backend_name: string; - // backend_show_name: string; - // from_config: boolean; - // default_version: string; - // default_backend_param: string[]; - // versions: string[]; - // }[]; - // }>(BACKEND_LIST_API, { - // method: 'GET' - // }); - return { - items: [ - { - backend_name: 'vllm', - backend_show_name: 'vLLM', - from_config: false, - default_version: '0.10.1.1', - default_backend_param: null, - versions: ['0.10.1.1', '0.10.0', '0.9.2', '0.8.5', '0.8.3'] - }, - { - backend_name: 'ascend-mindie', - backend_show_name: 'Ascend MindIE', - from_config: false, - default_version: null, - default_backend_param: null, - versions: null - }, - { - backend_name: 'custom', - backend_show_name: 'Custom', - from_config: false, - default_version: null, - default_backend_param: null, - versions: null - }, - { - backend_name: 'test', - backend_show_name: null, - from_config: true, - default_version: 'v1', - default_backend_param: ['--host=0.0.0.0'], - versions: ['v1'] - } - ] - }; + return request<{ + items: { + backend_name: string; + backend_show_name: string; + from_config: boolean; + default_version: string; + default_backend_param: string[]; + versions: string[]; + }[]; + }>(BACKEND_LIST_API, { + method: 'GET' + }); } diff --git a/src/pages/llmodels/components/table-list.tsx b/src/pages/llmodels/components/table-list.tsx index 034fc77b..7203d132 100644 --- a/src/pages/llmodels/components/table-list.tsx +++ b/src/pages/llmodels/components/table-list.tsx @@ -61,7 +61,7 @@ import useQueryBackends from '../hooks/use-query-backends'; import APIAccessInfoModal from './api-access-info'; import DeployModal from './deploy-modal'; import Instances from './instances'; -import UpdateModel from './update-modal'; +import UpdateModelModal from './update-modal'; import ViewLogsModal from './view-logs-modal'; interface ModelsProps { handleSearch: (params?: any) => void; @@ -685,7 +685,7 @@ const Models: React.FC = ({ }} > - = ({ onCancel={handleModalCancel} onOk={handleModalOk} backendOptions={backendOptions} - > + > { left={ + } placeholder={intl.formatMessage({ id: 'common.filter.name' })} style={{ width: 300 }} allowClear diff --git a/typings.d.ts b/typings.d.ts index ab486a8b..99e9bd25 100644 --- a/typings.d.ts +++ b/typings.d.ts @@ -27,5 +27,6 @@ declare module 'node-vibrant'; declare module 'lamejs'; declare module 'file-saver'; declare module 'tinycolor2'; +declare module 'js-yaml'; declare const REACT_APP_ENV: 'test' | 'dev' | 'pre' | false;