chore: show existing when add file
This commit is contained in:
@@ -55,6 +55,7 @@
|
|||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"mammoth": "^1.8.0",
|
"mammoth": "^1.8.0",
|
||||||
"marked": "^14.1.0",
|
"marked": "^14.1.0",
|
||||||
|
"minimatch": "^10.0.3",
|
||||||
"ml-dataset-iris": "^1.2.1",
|
"ml-dataset-iris": "^1.2.1",
|
||||||
"ml-pca": "^4.1.1",
|
"ml-pca": "^4.1.1",
|
||||||
"monaco-editor": "^0.53.0",
|
"monaco-editor": "^0.53.0",
|
||||||
|
|||||||
Generated
+22
@@ -126,6 +126,9 @@ dependencies:
|
|||||||
marked:
|
marked:
|
||||||
specifier: ^14.1.0
|
specifier: ^14.1.0
|
||||||
version: 14.1.4
|
version: 14.1.4
|
||||||
|
minimatch:
|
||||||
|
specifier: ^10.0.3
|
||||||
|
version: 10.0.3
|
||||||
ml-dataset-iris:
|
ml-dataset-iris:
|
||||||
specifier: ^1.2.1
|
specifier: ^1.2.1
|
||||||
version: 1.2.1
|
version: 1.2.1
|
||||||
@@ -2647,6 +2650,18 @@ packages:
|
|||||||
- supports-color
|
- supports-color
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@isaacs/balanced-match@4.0.1:
|
||||||
|
resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==, tarball: https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz}
|
||||||
|
engines: {node: 20 || >=22}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@isaacs/brace-expansion@5.0.0:
|
||||||
|
resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==, tarball: https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz}
|
||||||
|
engines: {node: 20 || >=22}
|
||||||
|
dependencies:
|
||||||
|
'@isaacs/balanced-match': 4.0.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@isaacs/cliui@8.0.2:
|
/@isaacs/cliui@8.0.2:
|
||||||
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==, tarball: https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz}
|
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==, tarball: https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
@@ -11096,6 +11111,13 @@ packages:
|
|||||||
resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==, tarball: https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz}
|
resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==, tarball: https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/minimatch@10.0.3:
|
||||||
|
resolution: {integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==, tarball: https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz}
|
||||||
|
engines: {node: 20 || >=22}
|
||||||
|
dependencies:
|
||||||
|
'@isaacs/brace-expansion': 5.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/minimatch@3.1.2:
|
/minimatch@3.1.2:
|
||||||
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==, tarball: https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz}
|
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==, tarball: https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|||||||
@@ -20,8 +20,9 @@ export const OverlayScroller: React.FC<
|
|||||||
maxHeight?: number;
|
maxHeight?: number;
|
||||||
style?: React.CSSProperties;
|
style?: React.CSSProperties;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
|
onScroll?: (e: React.UIEvent<HTMLDivElement, UIEvent>) => void;
|
||||||
}
|
}
|
||||||
> = ({ children, maxHeight, scrollbars, oppositeTheme, style }) => {
|
> = ({ children, maxHeight, scrollbars, oppositeTheme, style, onScroll }) => {
|
||||||
const scroller = React.useRef<any>(null);
|
const scroller = React.useRef<any>(null);
|
||||||
const { initialize } = useOverlayScroller({
|
const { initialize } = useOverlayScroller({
|
||||||
options: {
|
options: {
|
||||||
@@ -43,6 +44,7 @@ export const OverlayScroller: React.FC<
|
|||||||
className="overlay-scroller-wrapper"
|
className="overlay-scroller-wrapper"
|
||||||
$maxHeight={maxHeight || 200}
|
$maxHeight={maxHeight || 200}
|
||||||
hidden={false}
|
hidden={false}
|
||||||
|
onWheel={onScroll}
|
||||||
style={{
|
style={{
|
||||||
paddingInlineStart: 8,
|
paddingInlineStart: 8,
|
||||||
paddingInlineEnd: 8,
|
paddingInlineEnd: 8,
|
||||||
|
|||||||
+7
-7
@@ -1,11 +1,11 @@
|
|||||||
import { PageActionType, StatusType } from './types';
|
import { StatusType } from './types';
|
||||||
|
|
||||||
export const PageAction: Record<string, PageActionType> = {
|
export enum PageAction {
|
||||||
CREATE: 'create',
|
CREATE = 'create',
|
||||||
UPDATE: 'update',
|
UPDATE = 'update',
|
||||||
VIEW: 'view',
|
VIEW = 'view',
|
||||||
EDIT: 'edit'
|
EDIT = 'edit'
|
||||||
};
|
}
|
||||||
|
|
||||||
export const StatusColorMap: Record<
|
export const StatusColorMap: Record<
|
||||||
StatusType,
|
StatusType,
|
||||||
|
|||||||
@@ -94,5 +94,6 @@ export default {
|
|||||||
'resource.register.maos.support': 'Apple Silicon (M series), macOS 14+',
|
'resource.register.maos.support': 'Apple Silicon (M series), macOS 14+',
|
||||||
'resource.register.windows.support': 'win 10, win 11',
|
'resource.register.windows.support': 'win 10, win 11',
|
||||||
'resources.model.instance': 'Model Instance',
|
'resources.model.instance': 'Model Instance',
|
||||||
'resources.worker.download.privatekey': 'Download Private Key'
|
'resources.worker.download.privatekey': 'Download Private Key',
|
||||||
|
'resources.modelfiles.form.exsting': 'Existing'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -95,7 +95,8 @@ export default {
|
|||||||
'resource.register.windows.support': 'win 10, win 11',
|
'resource.register.windows.support': 'win 10, win 11',
|
||||||
'resources.model.instance': 'Model Instance',
|
'resources.model.instance': 'Model Instance',
|
||||||
'resources.worker.download.privatekey': 'Download Private Key',
|
'resources.worker.download.privatekey': 'Download Private Key',
|
||||||
'resources.worker': 'Worker'
|
'resources.worker': 'Worker',
|
||||||
|
'resources.modelfiles.form.exsting': 'Existing'
|
||||||
};
|
};
|
||||||
|
|
||||||
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
||||||
@@ -114,4 +115,5 @@ export default {
|
|||||||
// 13. 'resources.model.instance': 'Model Instance',
|
// 13. 'resources.model.instance': 'Model Instance',
|
||||||
// 14. 'resources.worker.download.privatekey': 'Download Private Key',
|
// 14. 'resources.worker.download.privatekey': 'Download Private Key',
|
||||||
// 15. 'resources.worker': 'Worker',
|
// 15. 'resources.worker': 'Worker',
|
||||||
|
// 16. 'resources.modelfiles.form.exsting': 'Existing'
|
||||||
// ========== End of To-Do List ==========
|
// ========== End of To-Do List ==========
|
||||||
|
|||||||
@@ -93,7 +93,8 @@ export default {
|
|||||||
'resource.register.windows.support': 'Windows 10, Windows 11',
|
'resource.register.windows.support': 'Windows 10, Windows 11',
|
||||||
'resources.model.instance': 'Модель экземпляра',
|
'resources.model.instance': 'Модель экземпляра',
|
||||||
'resources.worker.download.privatekey': 'Скачать приватный ключ',
|
'resources.worker.download.privatekey': 'Скачать приватный ключ',
|
||||||
'resources.worker': 'Worker'
|
'resources.worker': 'Worker',
|
||||||
|
'resources.modelfiles.form.exsting': 'Существующий'
|
||||||
};
|
};
|
||||||
|
|
||||||
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
||||||
|
|||||||
@@ -92,5 +92,6 @@ export default {
|
|||||||
'resource.register.maos.support': 'M 芯片,macOS 14+',
|
'resource.register.maos.support': 'M 芯片,macOS 14+',
|
||||||
'resource.register.windows.support': 'win 10, win 11',
|
'resource.register.windows.support': 'win 10, win 11',
|
||||||
'resources.model.instance': '模型实例',
|
'resources.model.instance': '模型实例',
|
||||||
'resources.worker.download.privatekey': '下载私钥'
|
'resources.worker.download.privatekey': '下载私钥',
|
||||||
|
'resources.modelfiles.form.exsting': '已存在'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ export default {
|
|||||||
'users.table.username': '用户名',
|
'users.table.username': '用户名',
|
||||||
'users.table.role': '角色',
|
'users.table.role': '角色',
|
||||||
'users.table.status': '状态',
|
'users.table.status': '状态',
|
||||||
'users.status.active': '激活',
|
'users.status.active': '启用',
|
||||||
'users.status.inactive': '禁用',
|
'users.status.inactive': '停用',
|
||||||
'users.form.active': '激活账户',
|
'users.form.active': '激活账户',
|
||||||
'users.form.active.description': '启用或禁用此用户账户',
|
'users.form.active.description': '启用或禁用此用户账户',
|
||||||
'users.form.fullname': '全名',
|
'users.form.fullname': '全名',
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ const SelectPanel: React.FC<SelectPanelProps> = ({
|
|||||||
</Button>
|
</Button>
|
||||||
</Header>
|
</Header>
|
||||||
<SelectedList
|
<SelectedList
|
||||||
maxHeight={height - 40}
|
maxHeight={height - 50}
|
||||||
selectedList={options.filter((item) =>
|
selectedList={options.filter((item) =>
|
||||||
selectedKeys.includes(item.key)
|
selectedKeys.includes(item.key)
|
||||||
)}
|
)}
|
||||||
@@ -194,7 +194,7 @@ const SelectPanel: React.FC<SelectPanelProps> = ({
|
|||||||
</Header>
|
</Header>
|
||||||
{showOptions.length > 0 ? (
|
{showOptions.length > 0 ? (
|
||||||
<List
|
<List
|
||||||
maxHeight={height - 40}
|
maxHeight={height - 50}
|
||||||
dataList={showOptions}
|
dataList={showOptions}
|
||||||
selectedKeys={selectedKeys}
|
selectedKeys={selectedKeys}
|
||||||
onSelectChange={handleSelectChange}
|
onSelectChange={handleSelectChange}
|
||||||
|
|||||||
@@ -547,6 +547,11 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
|||||||
>
|
>
|
||||||
<FormWrapper>
|
<FormWrapper>
|
||||||
<ColumnWrapper
|
<ColumnWrapper
|
||||||
|
styles={{
|
||||||
|
container: {
|
||||||
|
paddingTop: 0
|
||||||
|
}
|
||||||
|
}}
|
||||||
paddingBottom={
|
paddingBottom={
|
||||||
warningStatus.show
|
warningStatus.show
|
||||||
? Array.isArray(warningStatus.message)
|
? Array.isArray(warningStatus.message)
|
||||||
|
|||||||
@@ -8,13 +8,13 @@ import '../style/gpu-card.less';
|
|||||||
|
|
||||||
const CardWrapper = styled.div`
|
const CardWrapper = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 10px;
|
gap: 8px;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-bottom: 1px solid var(--ant-color-split);
|
border-bottom: 1px solid var(--ant-color-split);
|
||||||
padding-bottom: 10px;
|
padding-bottom: 5px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Header = styled.div`
|
const Header = styled.div`
|
||||||
@@ -25,7 +25,7 @@ const Description = styled.div`
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
gap: 10px;
|
gap: 8px;
|
||||||
color: var(--ant-color-text-tertiary);
|
color: var(--ant-color-text-tertiary);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import React, { useMemo } from 'react';
|
|||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { modelCategories, modelCategoriesMap, modelSourceMap } from '../config';
|
import { modelCategories, modelCategoriesMap, modelSourceMap } from '../config';
|
||||||
import { categoryToPathMap } from '../config/button-actions';
|
import { categoryToPathMap } from '../config/button-actions';
|
||||||
|
import { categoryConfig } from './model-tag';
|
||||||
|
|
||||||
const MyModelsStatusValueMap = {
|
const MyModelsStatusValueMap = {
|
||||||
Inactive: 'Inactive',
|
Inactive: 'Inactive',
|
||||||
@@ -198,10 +199,21 @@ const ModelItem: React.FC<{
|
|||||||
<div className="content">
|
<div className="content">
|
||||||
<div className="footer">
|
<div className="footer">
|
||||||
<div className="extra-info">
|
<div className="extra-info">
|
||||||
<ThemeTag className="tag-item" color="blue">
|
{model.categories?.length > 0 &&
|
||||||
{_.find(modelCategories, { value: model.categories?.[0] })
|
model.categories.map((sItem: string) => {
|
||||||
?.label || model.categories?.[0]}
|
return (
|
||||||
</ThemeTag>
|
<ThemeTag
|
||||||
|
icon={categoryConfig[sItem]?.icon}
|
||||||
|
key={sItem}
|
||||||
|
className="tag-item"
|
||||||
|
color={categoryConfig[sItem]?.color || 'blue'}
|
||||||
|
opacity={0.7}
|
||||||
|
>
|
||||||
|
{_.find(modelCategories, { value: sItem })?.label ||
|
||||||
|
sItem}
|
||||||
|
</ThemeTag>
|
||||||
|
);
|
||||||
|
})}
|
||||||
{maxToken > 0 && (
|
{maxToken > 0 && (
|
||||||
<ThemeTag className="tag-item" color="purple">
|
<ThemeTag className="tag-item" color="purple">
|
||||||
{maxToken}K context
|
{maxToken}K context
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
import { Tag } from 'antd';
|
import { Tag } from 'antd';
|
||||||
import { modelCategoriesMap } from '../config';
|
import { modelCategoriesMap } from '../config';
|
||||||
|
|
||||||
const categoryConfig = {
|
export const categoryConfig = {
|
||||||
[modelCategoriesMap.reranker]: {
|
[modelCategoriesMap.reranker]: {
|
||||||
icon: <IconFont type="icon-rank1" />,
|
icon: <IconFont type="icon-rank1" />,
|
||||||
color: 'cyan',
|
color: 'cyan',
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ type AddModalProps = {
|
|||||||
width?: string | number;
|
width?: string | number;
|
||||||
hasLinuxWorker?: boolean;
|
hasLinuxWorker?: boolean;
|
||||||
workerOptions: any[];
|
workerOptions: any[];
|
||||||
|
workersList?: any[];
|
||||||
onOk: (values: FormData) => void;
|
onOk: (values: FormData) => void;
|
||||||
onCancel: () => void;
|
onCancel: () => void;
|
||||||
};
|
};
|
||||||
@@ -47,7 +48,8 @@ const DownloadModel: React.FC<AddModalProps> = (props) => {
|
|||||||
hasLinuxWorker,
|
hasLinuxWorker,
|
||||||
source,
|
source,
|
||||||
width = 600,
|
width = 600,
|
||||||
workerOptions
|
workerOptions,
|
||||||
|
workersList
|
||||||
} = props || {};
|
} = props || {};
|
||||||
const SEARCH_SOURCE = [
|
const SEARCH_SOURCE = [
|
||||||
modelSourceMap.huggingface_value,
|
modelSourceMap.huggingface_value,
|
||||||
@@ -66,7 +68,7 @@ const DownloadModel: React.FC<AddModalProps> = (props) => {
|
|||||||
if (source === modelSourceMap.huggingface_value) {
|
if (source === modelSourceMap.huggingface_value) {
|
||||||
const huggingFaceModel = {
|
const huggingFaceModel = {
|
||||||
huggingface_repo_id: selectedModel.name,
|
huggingface_repo_id: selectedModel.name,
|
||||||
huggingface_filename: null
|
huggingface_filename: fileName || null
|
||||||
};
|
};
|
||||||
return huggingFaceModel;
|
return huggingFaceModel;
|
||||||
}
|
}
|
||||||
@@ -74,7 +76,7 @@ const DownloadModel: React.FC<AddModalProps> = (props) => {
|
|||||||
if (source === modelSourceMap.modelscope_value) {
|
if (source === modelSourceMap.modelscope_value) {
|
||||||
const modelScopeModel = {
|
const modelScopeModel = {
|
||||||
model_scope_model_id: selectedModel.name,
|
model_scope_model_id: selectedModel.name,
|
||||||
model_scope_file_path: null
|
model_scope_file_path: fileName || null
|
||||||
};
|
};
|
||||||
return modelScopeModel;
|
return modelScopeModel;
|
||||||
}
|
}
|
||||||
@@ -238,6 +240,9 @@ const DownloadModel: React.FC<AddModalProps> = (props) => {
|
|||||||
ref={form}
|
ref={form}
|
||||||
onOk={handleOk}
|
onOk={handleOk}
|
||||||
source={source}
|
source={source}
|
||||||
|
selectedModel={selectedModel}
|
||||||
|
fileName={fileName}
|
||||||
|
workersList={workersList}
|
||||||
workerOptions={workerOptions}
|
workerOptions={workerOptions}
|
||||||
></TargetForm>
|
></TargetForm>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -7,22 +7,64 @@ import { ModelFileFormData as FormData } from '@/pages/resources/config/types';
|
|||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Form } from 'antd';
|
import { Form } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import React, { forwardRef, useImperativeHandle, useMemo } from 'react';
|
import { minimatch } from 'minimatch';
|
||||||
|
import React, {
|
||||||
|
forwardRef,
|
||||||
|
useEffect,
|
||||||
|
useImperativeHandle,
|
||||||
|
useMemo
|
||||||
|
} from 'react';
|
||||||
import { localPathTipsList, modelSourceMap, sourceOptions } from '../config';
|
import { localPathTipsList, modelSourceMap, sourceOptions } from '../config';
|
||||||
|
import { useGenerateWorkersModelFileOptions } from '../hooks';
|
||||||
|
|
||||||
|
type EmptyObject = Record<never, never>;
|
||||||
|
|
||||||
|
type CascaderOption<T extends object = EmptyObject> = {
|
||||||
|
label: string;
|
||||||
|
value: string | number;
|
||||||
|
parent?: boolean;
|
||||||
|
disabled?: boolean;
|
||||||
|
index?: number;
|
||||||
|
children?: CascaderOption<T>[];
|
||||||
|
} & Partial<T>;
|
||||||
|
|
||||||
interface TargetFormProps {
|
interface TargetFormProps {
|
||||||
ref?: any;
|
ref?: any;
|
||||||
source: string;
|
source: string;
|
||||||
workerOptions: any[];
|
workerOptions: CascaderOption<{ state: string }>[];
|
||||||
|
workersList?: Global.BaseOption<
|
||||||
|
number,
|
||||||
|
{ state: string; labels: Record<string, string>; cluster_id: number }
|
||||||
|
>[];
|
||||||
|
selectedModel?: Record<string, any>;
|
||||||
|
fileName?: string;
|
||||||
onOk: (values: any) => void;
|
onOk: (values: any) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TargetForm: React.FC<TargetFormProps> = forwardRef((props, ref) => {
|
const TargetForm: React.FC<TargetFormProps> = forwardRef((props, ref) => {
|
||||||
const { onOk, source, workerOptions } = props;
|
const {
|
||||||
|
modelFileOptions,
|
||||||
|
getModelFileList,
|
||||||
|
generateWorkersModelFileOptions
|
||||||
|
} = useGenerateWorkersModelFileOptions();
|
||||||
|
const { onOk, source, workerOptions, workersList, selectedModel, fileName } =
|
||||||
|
props;
|
||||||
const { getRuleMessage } = useAppUtils();
|
const { getRuleMessage } = useAppUtils();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const init = async () => {
|
||||||
|
try {
|
||||||
|
if (workersList && workersList?.length > 0) {
|
||||||
|
const modelFiles = await getModelFileList();
|
||||||
|
generateWorkersModelFileOptions(modelFiles, workersList || []);
|
||||||
|
}
|
||||||
|
} catch (error) {}
|
||||||
|
};
|
||||||
|
init();
|
||||||
|
}, [workersList]);
|
||||||
|
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
form
|
form
|
||||||
}));
|
}));
|
||||||
@@ -33,10 +75,6 @@ const TargetForm: React.FC<TargetFormProps> = forwardRef((props, ref) => {
|
|||||||
...data,
|
...data,
|
||||||
worker_id: data.worker_id?.[1]
|
worker_id: data.worker_id?.[1]
|
||||||
});
|
});
|
||||||
console.log('Form Data: ', {
|
|
||||||
...data,
|
|
||||||
worker_id: data.worker_id?.[1]
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOnLocalPathBlur = (e: any) => {
|
const handleOnLocalPathBlur = (e: any) => {
|
||||||
@@ -49,6 +87,32 @@ const TargetForm: React.FC<TargetFormProps> = forwardRef((props, ref) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const renderOptionNode = (props: { data: any }) => {
|
||||||
|
const { data } = props;
|
||||||
|
const currentWorker = modelFileOptions.find(
|
||||||
|
(item) => item.value === data.value
|
||||||
|
);
|
||||||
|
|
||||||
|
const isExisting = currentWorker?.children?.some((child) => {
|
||||||
|
const isSameFile =
|
||||||
|
child.fileName === (fileName || '') ||
|
||||||
|
minimatch(child.fileName || '', fileName || '');
|
||||||
|
|
||||||
|
return child.repoId === selectedModel?.name && isSameFile;
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
{data.label}
|
||||||
|
{isExisting && (
|
||||||
|
<span className="text-tertiary m-l-4">
|
||||||
|
({intl.formatMessage({ id: 'resources.modelfiles.form.exsting' })})
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const renderLocalPathFields = () => {
|
const renderLocalPathFields = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -136,6 +200,7 @@ const TargetForm: React.FC<TargetFormProps> = forwardRef((props, ref) => {
|
|||||||
label={intl.formatMessage({ id: 'resources.worker' })}
|
label={intl.formatMessage({ id: 'resources.worker' })}
|
||||||
options={workerOptions}
|
options={workerOptions}
|
||||||
showCheckedStrategy="SHOW_CHILD"
|
showCheckedStrategy="SHOW_CHILD"
|
||||||
|
optionNode={renderOptionNode}
|
||||||
getPopupContainer={(triggerNode) => triggerNode.parentNode}
|
getPopupContainer={(triggerNode) => triggerNode.parentNode}
|
||||||
></SealCascader>
|
></SealCascader>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { PageAction } from '@/config';
|
||||||
import { PageActionType } from '@/config/types';
|
import { PageActionType } from '@/config/types';
|
||||||
import CollapsePanel from '@/pages/_components/collapse-panel';
|
import CollapsePanel from '@/pages/_components/collapse-panel';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
@@ -122,22 +123,21 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
|
|||||||
|
|
||||||
const SegmentedTop = useMemo(() => {
|
const SegmentedTop = useMemo(() => {
|
||||||
if (
|
if (
|
||||||
[
|
modelSourceMap.local_path_value === source ||
|
||||||
modelSourceMap.huggingface_value,
|
action === PageAction.EDIT ||
|
||||||
modelSourceMap.modelscope_value
|
formKey === deployFormKeyMap.catalog
|
||||||
].includes(source) &&
|
|
||||||
formKey === deployFormKeyMap.deployment
|
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
top: 50,
|
top: 0,
|
||||||
offsetTop: 146
|
offsetTop: 96
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
top: 0,
|
top: 50,
|
||||||
offsetTop: 96
|
offsetTop: 146
|
||||||
};
|
};
|
||||||
}, [source, formKey]);
|
}, [source, formKey, action]);
|
||||||
|
|
||||||
const handleSumit = () => {
|
const handleSumit = () => {
|
||||||
form.submit();
|
form.submit();
|
||||||
|
|||||||
@@ -98,7 +98,6 @@ const LocalPathForm: React.FC = () => {
|
|||||||
<SealInput.Input
|
<SealInput.Input
|
||||||
allowClear
|
allowClear
|
||||||
required
|
required
|
||||||
onBlur={handleOnBlur}
|
|
||||||
onFocus={handleOnFocus}
|
onFocus={handleOnFocus}
|
||||||
label={intl.formatMessage({ id: 'models.form.filePath' })}
|
label={intl.formatMessage({ id: 'models.form.filePath' })}
|
||||||
description={<TooltipList list={localPathTipsList}></TooltipList>}
|
description={<TooltipList list={localPathTipsList}></TooltipList>}
|
||||||
|
|||||||
@@ -94,6 +94,14 @@ const ScheduleTypeForm: React.FC = () => {
|
|||||||
const handleOnStepReplica = (value: number | null) => {
|
const handleOnStepReplica = (value: number | null) => {
|
||||||
if (value === null) {
|
if (value === null) {
|
||||||
form.setFieldValue(['gpu_selector', 'gpus_per_replica'], 1);
|
form.setFieldValue(['gpu_selector', 'gpus_per_replica'], 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isPowerOfTwo = (n: number) => (n & (n - 1)) === 0 && n !== 0; // check power of two
|
||||||
|
if (!isPowerOfTwo(value)) {
|
||||||
|
const newValue = Math.pow(2, Math.round(Math.log2(value)));
|
||||||
|
form.setFieldValue(['gpu_selector', 'gpus_per_replica'], newValue);
|
||||||
|
onValuesChange?.({}, form.getFieldsValue());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -25,12 +25,27 @@ export type MessageStatus = {
|
|||||||
evaluateResult?: EvaluateResult;
|
evaluateResult?: EvaluateResult;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export interface ModelFileOption {
|
||||||
|
label: string;
|
||||||
|
value: number;
|
||||||
|
labels?: Record<string, string>;
|
||||||
|
parent: boolean;
|
||||||
|
repoId?: string;
|
||||||
|
fileName?: string;
|
||||||
|
[key: string]: any;
|
||||||
|
children?: ModelFileOption[];
|
||||||
|
}
|
||||||
|
|
||||||
export type WarningStausOptions = {
|
export type WarningStausOptions = {
|
||||||
lockAfterUpdate?: boolean;
|
lockAfterUpdate?: boolean;
|
||||||
override?: boolean;
|
override?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useGenerateModelFileOptions = () => {
|
export const useGenerateWorkersModelFileOptions = () => {
|
||||||
|
const [modelFileOptions, setModelFileOptions] = useState<ModelFileOption[]>(
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
const getModelFileList = async () => {
|
const getModelFileList = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await queryModelFilesList({ page: 1, perPage: 100 });
|
const res = await queryModelFilesList({ page: 1, perPage: 100 });
|
||||||
@@ -42,7 +57,7 @@ export const useGenerateModelFileOptions = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const generateModelFileOptions = (list: any[], workerList: any[]) => {
|
const generateWorkersModelFileOptions = (list: any[], workerList: any[]) => {
|
||||||
const workerFields = new Set(['name', 'id', 'ip', 'status']);
|
const workerFields = new Set(['name', 'id', 'ip', 'status']);
|
||||||
const workersMap = new Map<number, WorkerListItem>();
|
const workersMap = new Map<number, WorkerListItem>();
|
||||||
|
|
||||||
@@ -54,7 +69,7 @@ export const useGenerateModelFileOptions = () => {
|
|||||||
|
|
||||||
const result = Array.from(workersMap.values()).map((worker) => ({
|
const result = Array.from(workersMap.values()).map((worker) => ({
|
||||||
label: worker.name,
|
label: worker.name,
|
||||||
value: worker.name,
|
value: worker.id,
|
||||||
labels: worker.labels,
|
labels: worker.labels,
|
||||||
parent: true,
|
parent: true,
|
||||||
children: list
|
children: list
|
||||||
@@ -63,18 +78,16 @@ export const useGenerateModelFileOptions = () => {
|
|||||||
item.worker_id === worker.id && !!item.resolved_paths?.length
|
item.worker_id === worker.id && !!item.resolved_paths?.length
|
||||||
)
|
)
|
||||||
.map((item) => {
|
.map((item) => {
|
||||||
const resolved_paths =
|
|
||||||
Array.isArray(item.resolved_paths) && item.resolved_paths.length
|
|
||||||
? item.resolved_paths[0].split('/')
|
|
||||||
: [];
|
|
||||||
const label =
|
|
||||||
resolved_paths.length > 0 ? resolved_paths.pop() : 'Unknown File';
|
|
||||||
return {
|
return {
|
||||||
label: item.resolved_paths[0] || '',
|
label: item.resolved_paths[0] || '',
|
||||||
value: item.resolved_paths[0] || '',
|
value: item.resolved_paths[0] || '',
|
||||||
worker_labels: worker.labels,
|
|
||||||
worker_name: worker.name,
|
|
||||||
parent: false,
|
parent: false,
|
||||||
|
repoId: item.huggingface_repo_id || item.model_scope_model_id || '',
|
||||||
|
fileName:
|
||||||
|
item.huggingface_filename ||
|
||||||
|
item.model_scope_file_path ||
|
||||||
|
item.local_path ||
|
||||||
|
'',
|
||||||
...item
|
...item
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
@@ -95,12 +108,15 @@ export const useGenerateModelFileOptions = () => {
|
|||||||
return acc;
|
return acc;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
setModelFileOptions(result);
|
||||||
|
|
||||||
return childrenList;
|
return childrenList;
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getModelFileList,
|
getModelFileList,
|
||||||
generateModelFileOptions
|
modelFileOptions,
|
||||||
|
generateWorkersModelFileOptions
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { GPUListItem, ListItem } from '../config/types';
|
|||||||
|
|
||||||
type EmptyObject = Record<never, never>;
|
type EmptyObject = Record<never, never>;
|
||||||
|
|
||||||
type CascaderOption<T extends object = EmptyObject> = {
|
export type CascaderOption<T extends object = EmptyObject> = {
|
||||||
label: string;
|
label: string;
|
||||||
value: string | number;
|
value: string | number;
|
||||||
parent?: boolean;
|
parent?: boolean;
|
||||||
@@ -210,7 +210,10 @@ export const useGenerateWorkerOptions = () => {
|
|||||||
cluster_id: item.cluster_id,
|
cluster_id: item.cluster_id,
|
||||||
state: item.state,
|
state: item.state,
|
||||||
label: item.name,
|
label: item.name,
|
||||||
value: item.id
|
value: item.id,
|
||||||
|
id: item.id,
|
||||||
|
labels: item.labels || {},
|
||||||
|
name: item.name
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
setClusterList(
|
setClusterList(
|
||||||
|
|||||||
@@ -349,6 +349,7 @@ const ModelFiles = () => {
|
|||||||
width={downloadModalStatus.width}
|
width={downloadModalStatus.width}
|
||||||
hasLinuxWorker={downloadModalStatus.hasLinuxWorker}
|
hasLinuxWorker={downloadModalStatus.hasLinuxWorker}
|
||||||
workerOptions={readyWorkers}
|
workerOptions={readyWorkers}
|
||||||
|
workersList={workersList}
|
||||||
></DownloadModal>
|
></DownloadModal>
|
||||||
<DeployModal
|
<DeployModal
|
||||||
deploymentType="modelFiles"
|
deploymentType="modelFiles"
|
||||||
|
|||||||
@@ -161,6 +161,7 @@ const getModelInfo = (record: ListItem) => {
|
|||||||
filename: record.huggingface_filename || record.huggingface_repo_id
|
filename: record.huggingface_filename || record.huggingface_repo_id
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (record.source === modelSourceMap.modelscope_value) {
|
if (record.source === modelSourceMap.modelscope_value) {
|
||||||
return {
|
return {
|
||||||
source: `${source}/${record.model_scope_model_id}`,
|
source: `${source}/${record.model_scope_model_id}`,
|
||||||
@@ -169,14 +170,7 @@ const getModelInfo = (record: ListItem) => {
|
|||||||
filename: record.model_scope_file_path || record.model_scope_model_id
|
filename: record.model_scope_file_path || record.model_scope_model_id
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (record.source === modelSourceMap.ollama_library_value) {
|
|
||||||
return {
|
|
||||||
source: `${source}/${record.ollama_library_model_name}`,
|
|
||||||
repo_id: record.ollama_library_model_name,
|
|
||||||
title: record.ollama_library_model_name,
|
|
||||||
filename: record.ollama_library_model_name
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
source: `${source}${record.local_path}`,
|
source: `${source}${record.local_path}`,
|
||||||
repo_id: record.local_path,
|
repo_id: record.local_path,
|
||||||
@@ -275,7 +269,7 @@ const useFilesColumns = (props: {
|
|||||||
},
|
},
|
||||||
render: (text: string, record: ListItem) => {
|
render: (text: string, record: ListItem) => {
|
||||||
const modelInfo = getModelInfo(record);
|
const modelInfo = getModelInfo(record);
|
||||||
const { repo_id, source } = modelInfo;
|
const { source } = modelInfo;
|
||||||
return (
|
return (
|
||||||
<TextWrapper style={{ paddingRight: 8 }}>
|
<TextWrapper style={{ paddingRight: 8 }}>
|
||||||
<AutoTooltip ghost title={source}>
|
<AutoTooltip ghost title={source}>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import SealSelect from '@/components/seal-form/seal-select';
|
|||||||
import SealSwitch from '@/components/seal-form/seal-switch';
|
import SealSwitch from '@/components/seal-form/seal-switch';
|
||||||
import { PageAction, PasswordReg } from '@/config';
|
import { PageAction, PasswordReg } from '@/config';
|
||||||
import { PageActionType } from '@/config/types';
|
import { PageActionType } from '@/config/types';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl, useModel } from '@umijs/max';
|
||||||
import { Form, Select } from 'antd';
|
import { Form, Select } from 'antd';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { UserRoles, UserRolesOptions } from '../config';
|
import { UserRoles, UserRolesOptions } from '../config';
|
||||||
@@ -28,6 +28,7 @@ const AddModal: React.FC<AddModalProps> = ({
|
|||||||
data,
|
data,
|
||||||
onCancel
|
onCancel
|
||||||
}) => {
|
}) => {
|
||||||
|
const { initialState } = useModel('@@initialState') || {};
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
@@ -125,20 +126,23 @@ const AddModal: React.FC<AddModalProps> = ({
|
|||||||
</SealSelect>
|
</SealSelect>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ flex: 1 }}>
|
{(data?.id !== initialState?.currentUser?.id ||
|
||||||
<Form.Item<FormData>
|
action === PageAction.CREATE) && (
|
||||||
name="is_active"
|
<div style={{ flex: 1 }}>
|
||||||
rules={[{ required: false }]}
|
<Form.Item<FormData>
|
||||||
valuePropName="checked"
|
name="is_active"
|
||||||
>
|
rules={[{ required: false }]}
|
||||||
<SealSwitch
|
valuePropName="checked"
|
||||||
label={intl.formatMessage({ id: 'users.form.active' })}
|
>
|
||||||
description={intl.formatMessage({
|
<SealSwitch
|
||||||
id: 'users.form.active.description'
|
label={intl.formatMessage({ id: 'users.form.active' })}
|
||||||
})}
|
description={intl.formatMessage({
|
||||||
/>
|
id: 'users.form.active.description'
|
||||||
</Form.Item>
|
})}
|
||||||
</div>
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Form.Item<FormData>
|
<Form.Item<FormData>
|
||||||
|
|||||||
@@ -109,20 +109,37 @@ const useUsersColumns = ({
|
|||||||
render: (text: string, record: ListItem) => {
|
render: (text: string, record: ListItem) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Tag
|
{record.is_active ? (
|
||||||
style={{
|
<Tag
|
||||||
marginRight: 0,
|
style={{
|
||||||
paddingInline: 12,
|
marginRight: 0,
|
||||||
borderRadius: 12
|
paddingInline: 12,
|
||||||
}}
|
borderRadius: 12,
|
||||||
color={record.is_active ? 'success' : 'default'}
|
background: 'unset',
|
||||||
>
|
borderColor: 'var(--ant-color-success)'
|
||||||
{intl.formatMessage({
|
}}
|
||||||
id: record.is_active
|
color="success"
|
||||||
? 'users.status.active'
|
>
|
||||||
: 'users.status.inactive'
|
{intl.formatMessage({
|
||||||
})}
|
id: 'users.status.active'
|
||||||
</Tag>
|
})}
|
||||||
|
</Tag>
|
||||||
|
) : (
|
||||||
|
<Tag
|
||||||
|
style={{
|
||||||
|
marginRight: 0,
|
||||||
|
paddingInline: 12,
|
||||||
|
borderRadius: 12,
|
||||||
|
background: 'unset',
|
||||||
|
color: 'var(--ant-color-text-description)'
|
||||||
|
}}
|
||||||
|
color="default"
|
||||||
|
>
|
||||||
|
{intl.formatMessage({
|
||||||
|
id: 'users.status.inactive'
|
||||||
|
})}
|
||||||
|
</Tag>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user