feat: duplicate deployment
This commit is contained in:
+14
-14
@@ -86,14 +86,14 @@ export default [
|
|||||||
redirect: '/models/deployments'
|
redirect: '/models/deployments'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'routes',
|
name: 'modelCatalog',
|
||||||
path: '/models/routes',
|
path: '/models/catalog',
|
||||||
key: 'routes',
|
key: 'modelsCatalog',
|
||||||
icon: 'icon-captive_portal',
|
icon: 'icon-layers',
|
||||||
selectedIcon: 'icon-captive_portal',
|
selectedIcon: 'icon-layers-filled',
|
||||||
defaultIcon: 'icon-captive_portal',
|
defaultIcon: 'icon-layers',
|
||||||
access: 'canSeeAdmin',
|
access: 'canSeeAdmin',
|
||||||
component: './model-routes/index'
|
component: './llmodels/catalog'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'deployment',
|
name: 'deployment',
|
||||||
@@ -106,14 +106,14 @@ export default [
|
|||||||
component: './llmodels/index'
|
component: './llmodels/index'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'modelCatalog',
|
name: 'routes',
|
||||||
path: '/models/catalog',
|
path: '/models/routes',
|
||||||
key: 'modelsCatalog',
|
key: 'routes',
|
||||||
icon: 'icon-layers',
|
icon: 'icon-captive_portal',
|
||||||
selectedIcon: 'icon-layers-filled',
|
selectedIcon: 'icon-captive_portal',
|
||||||
defaultIcon: 'icon-layers',
|
defaultIcon: 'icon-captive_portal',
|
||||||
access: 'canSeeAdmin',
|
access: 'canSeeAdmin',
|
||||||
component: './llmodels/catalog'
|
component: './model-routes/index'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'providers',
|
name: 'providers',
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { getAtomStorage } from '@/atoms/utils';
|
|||||||
import VersionInfo, { modalConfig } from '@/components/version-info';
|
import VersionInfo, { modalConfig } from '@/components/version-info';
|
||||||
import externalLinks from '@/constants/external-links';
|
import externalLinks from '@/constants/external-links';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Button, Divider, Modal } from 'antd';
|
import { Button, Divider, Modal, Typography } from 'antd';
|
||||||
import { createStyles } from 'antd-style';
|
import { createStyles } from 'antd-style';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
@@ -54,7 +54,13 @@ const Footer: React.FC = () => {
|
|||||||
<CompanyWrapper>
|
<CompanyWrapper>
|
||||||
<span>©</span>
|
<span>©</span>
|
||||||
<span> {new Date().getFullYear()}</span>
|
<span> {new Date().getFullYear()}</span>
|
||||||
<span> {intl.formatMessage({ id: 'settings.company' })}</span>
|
<Typography.Link
|
||||||
|
href="https://gpustack.ai"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
{intl.formatMessage({ id: 'settings.company' })}
|
||||||
|
</Typography.Link>
|
||||||
</CompanyWrapper>
|
</CompanyWrapper>
|
||||||
<Divider orientation="vertical" />
|
<Divider orientation="vertical" />
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { useEffect, useRef, useState } from 'react';
|
|||||||
|
|
||||||
* generic hook to query data list
|
* generic hook to query data list
|
||||||
* @template ListItem
|
* @template ListItem
|
||||||
|
* @param Params - query params type, e.g. { page: number; perPage: number }
|
||||||
* @param option.fetchList: (params, extra) => Promise<{ items: ListItem[] }>
|
* @param option.fetchList: (params, extra) => Promise<{ items: ListItem[] }>
|
||||||
* @returns loading, dataList, fetchData, cancelRequest
|
* @returns loading, dataList, fetchData, cancelRequest
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ export default {
|
|||||||
'common.form.password': 'Password',
|
'common.form.password': 'Password',
|
||||||
'common.form.username': 'Username',
|
'common.form.username': 'Username',
|
||||||
'common.login.rember': 'Remember me',
|
'common.login.rember': 'Remember me',
|
||||||
'settings.company': 'SEAL',
|
'settings.company': 'GPUStack.ai',
|
||||||
'common.button.help': 'Help',
|
'common.button.help': 'Help',
|
||||||
'common.button.feedback': 'Feedback',
|
'common.button.feedback': 'Feedback',
|
||||||
'common.button.docs': 'Documentation',
|
'common.button.docs': 'Documentation',
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ export default {
|
|||||||
'models.button.deploy': 'Deploy Model',
|
'models.button.deploy': 'Deploy Model',
|
||||||
'models.title': 'Models',
|
'models.title': 'Models',
|
||||||
'models.title.edit': 'Edit Model',
|
'models.title.edit': 'Edit Model',
|
||||||
|
'models.title.duplicate': 'Duplicate Model',
|
||||||
'models.table.models': 'models',
|
'models.table.models': 'models',
|
||||||
'models.table.name': 'Model Name',
|
'models.table.name': 'Model Name',
|
||||||
'models.form.source': 'Source',
|
'models.form.source': 'Source',
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ export default {
|
|||||||
'common.form.password': 'パスワード',
|
'common.form.password': 'パスワード',
|
||||||
'common.form.username': 'ユーザー名',
|
'common.form.username': 'ユーザー名',
|
||||||
'common.login.rember': 'ログイン状態を保持',
|
'common.login.rember': 'ログイン状態を保持',
|
||||||
'settings.company': 'SEAL',
|
'settings.company': 'GPUStack.ai',
|
||||||
'common.button.help': 'ヘルプ',
|
'common.button.help': 'ヘルプ',
|
||||||
'common.button.feedback': 'フィードバック',
|
'common.button.feedback': 'フィードバック',
|
||||||
'common.button.docs': 'ドキュメント',
|
'common.button.docs': 'ドキュメント',
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ export default {
|
|||||||
'models.button.deploy': 'モデルをデプロイ',
|
'models.button.deploy': 'モデルをデプロイ',
|
||||||
'models.title': 'モデル',
|
'models.title': 'モデル',
|
||||||
'models.title.edit': 'モデルを編集',
|
'models.title.edit': 'モデルを編集',
|
||||||
|
'models.title.duplicate': 'モデルを複製',
|
||||||
'models.table.models': 'モデル',
|
'models.table.models': 'モデル',
|
||||||
'models.table.name': 'モデル名',
|
'models.table.name': 'モデル名',
|
||||||
'models.form.source': 'ソース',
|
'models.form.source': 'ソース',
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ export default {
|
|||||||
'common.form.password': 'Пароль',
|
'common.form.password': 'Пароль',
|
||||||
'common.form.username': 'Имя пользователя',
|
'common.form.username': 'Имя пользователя',
|
||||||
'common.login.rember': 'Запомнить меня',
|
'common.login.rember': 'Запомнить меня',
|
||||||
'settings.company': 'SEAL',
|
'settings.company': 'GPUStack.ai',
|
||||||
'common.button.help': 'Помощь',
|
'common.button.help': 'Помощь',
|
||||||
'common.button.feedback': 'Обратная связь',
|
'common.button.feedback': 'Обратная связь',
|
||||||
'common.button.docs': 'Документация',
|
'common.button.docs': 'Документация',
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ export default {
|
|||||||
'models.button.deploy': 'Развернуть модель',
|
'models.button.deploy': 'Развернуть модель',
|
||||||
'models.title': 'Модели',
|
'models.title': 'Модели',
|
||||||
'models.title.edit': 'Редактировать модель',
|
'models.title.edit': 'Редактировать модель',
|
||||||
|
'models.title.duplicate': 'Дублировать модель',
|
||||||
'models.table.models': 'Модели',
|
'models.table.models': 'Модели',
|
||||||
'models.table.name': 'Название модели',
|
'models.table.name': 'Название модели',
|
||||||
'models.form.source': 'Источник',
|
'models.form.source': 'Источник',
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ export default {
|
|||||||
'models.button.deploy': '部署模型',
|
'models.button.deploy': '部署模型',
|
||||||
'models.title': '模型',
|
'models.title': '模型',
|
||||||
'models.title.edit': '编辑模型',
|
'models.title.edit': '编辑模型',
|
||||||
|
'models.title.duplicate': '复制模型',
|
||||||
'models.table.models': '模型',
|
'models.table.models': '模型',
|
||||||
'models.table.name': '模型名称',
|
'models.table.name': '模型名称',
|
||||||
'models.form.source': '来源',
|
'models.form.source': '来源',
|
||||||
|
|||||||
@@ -27,7 +27,12 @@ import _ from 'lodash';
|
|||||||
import React, { useCallback, useEffect, useMemo } from 'react';
|
import React, { useCallback, useEffect, useMemo } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { MODEL_INSTANCE_API } from '../apis';
|
import { MODEL_INSTANCE_API } from '../apis';
|
||||||
import { InstanceStatusMap, InstanceStatusMapValue, status } from '../config';
|
import {
|
||||||
|
InstanceStatusMap,
|
||||||
|
InstanceStatusMapValue,
|
||||||
|
modelCategoriesMap,
|
||||||
|
status
|
||||||
|
} from '../config';
|
||||||
import { backendOptionsMap } from '../config/backend-parameters';
|
import { backendOptionsMap } from '../config/backend-parameters';
|
||||||
import { generateSource } from '../config/button-actions';
|
import { generateSource } from '../config/button-actions';
|
||||||
import {
|
import {
|
||||||
@@ -431,12 +436,18 @@ const InstanceItem: React.FC<InstanceItemProps> = ({
|
|||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const actionItems = useMemo(() => {
|
const actionItems = useMemo(() => {
|
||||||
return _.filter(childActionList, (action: any) => {
|
return _.filter(childActionList, (action: any) => {
|
||||||
|
if (action.key === 'benchmark') {
|
||||||
|
return (
|
||||||
|
action.status.includes(instanceData.state) &&
|
||||||
|
modelData?.categories?.includes(modelCategoriesMap.llm)
|
||||||
|
);
|
||||||
|
}
|
||||||
if (action.status && action.status.length > 0) {
|
if (action.status && action.status.length > 0) {
|
||||||
return action.status.includes(instanceData.state);
|
return action.status.includes(instanceData.state);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}, [instanceData.state]);
|
}, [instanceData.state, modelData]);
|
||||||
|
|
||||||
const createFileName = (name: string) => {
|
const createFileName = (name: string) => {
|
||||||
const timestamp = dayjs().format('YYYY-MM-DD_HH-mm-ss');
|
const timestamp = dayjs().format('YYYY-MM-DD_HH-mm-ss');
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ import useExpandedRowKeys from '@/hooks/use-expanded-row-keys';
|
|||||||
import useTableRowSelection from '@/hooks/use-table-row-selection';
|
import useTableRowSelection from '@/hooks/use-table-row-selection';
|
||||||
import PageBox from '@/pages/_components/page-box';
|
import PageBox from '@/pages/_components/page-box';
|
||||||
import useNoResourceResult from '@/pages/llmodels/hooks/use-no-resource-result';
|
import useNoResourceResult from '@/pages/llmodels/hooks/use-no-resource-result';
|
||||||
|
import { TargetStatusValueMap } from '@/pages/model-routes/config';
|
||||||
|
import useOpenPlayground from '@/pages/model-routes/hooks/use-open-playground';
|
||||||
|
import useQueryTargets from '@/pages/model-routes/services/use-query-targets';
|
||||||
import { handleBatchRequest } from '@/utils';
|
import { handleBatchRequest } from '@/utils';
|
||||||
import { DownOutlined, SearchOutlined, SyncOutlined } from '@ant-design/icons';
|
import { DownOutlined, SearchOutlined, SyncOutlined } from '@ant-design/icons';
|
||||||
import { useIntl, useNavigate, useSearchParams } from '@umijs/max';
|
import { useIntl, useNavigate, useSearchParams } from '@umijs/max';
|
||||||
@@ -54,11 +57,10 @@ import {
|
|||||||
ModelInstanceListItem,
|
ModelInstanceListItem,
|
||||||
SourceType
|
SourceType
|
||||||
} from '../config/types';
|
} from '../config/types';
|
||||||
|
import useEditDeployment from '../hooks/use-edit-deployment';
|
||||||
import useFilterStatus from '../hooks/use-filter-status';
|
import useFilterStatus from '../hooks/use-filter-status';
|
||||||
import useFormInitialValues from '../hooks/use-form-initial-values';
|
import useFormInitialValues from '../hooks/use-form-initial-values';
|
||||||
import useModelsColumns from '../hooks/use-models-columns';
|
import useModelsColumns from '../hooks/use-models-columns';
|
||||||
import AccessControlModal from './access-control-modal';
|
|
||||||
import APIAccessInfoModal from './api-access-info';
|
|
||||||
import DeployModal from './deploy-modal';
|
import DeployModal from './deploy-modal';
|
||||||
import Instances from './instances';
|
import Instances from './instances';
|
||||||
import UpdateModelModal from './update-modal';
|
import UpdateModelModal from './update-modal';
|
||||||
@@ -140,13 +142,12 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
const page = searchParams.get('page');
|
const page = searchParams.get('page');
|
||||||
const { saveScrollHeight, restoreScrollHeight } = useBodyScroll();
|
const { saveScrollHeight, restoreScrollHeight } = useBodyScroll();
|
||||||
const [updateFormInitials, setUpdateFormInitials] = useState<{
|
const {
|
||||||
data: any;
|
openEditModalStatus,
|
||||||
isGGUF: boolean;
|
openEditModal,
|
||||||
}>({
|
openDuplicateModal,
|
||||||
data: {},
|
closeEditModal
|
||||||
isGGUF: false
|
} = useEditDeployment();
|
||||||
});
|
|
||||||
const [expandAtom, setExpandAtom] = useAtom(modelsExpandKeysAtom);
|
const [expandAtom, setExpandAtom] = useAtom(modelsExpandKeysAtom);
|
||||||
const [modelsSession, setModelsSession] = useAtom(modelsSessionAtom);
|
const [modelsSession, setModelsSession] = useAtom(modelsSessionAtom);
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
@@ -159,17 +160,18 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
removeExpandedRowKey,
|
removeExpandedRowKey,
|
||||||
expandedRowKeys
|
expandedRowKeys
|
||||||
} = useExpandedRowKeys(expandAtom);
|
} = useExpandedRowKeys(expandAtom);
|
||||||
|
const { handleOpenPlayGround } = useOpenPlayground();
|
||||||
const { labelRender, optionRender, handleStatusChange, statusOptions } =
|
const { labelRender, optionRender, handleStatusChange, statusOptions } =
|
||||||
useFilterStatus({
|
useFilterStatus({
|
||||||
onStatusChange: onStatusChange
|
onStatusChange: onStatusChange
|
||||||
});
|
});
|
||||||
|
const { fetchData: fetchTargets, dataList: targetList } = useQueryTargets();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchTargets({});
|
||||||
|
}, []);
|
||||||
|
|
||||||
const [apiAccessInfo, setAPIAccessInfo] = useState<any>({
|
|
||||||
show: false,
|
|
||||||
data: {}
|
|
||||||
});
|
|
||||||
const [openLogModal, setOpenLogModal] = useState(false);
|
const [openLogModal, setOpenLogModal] = useState(false);
|
||||||
const [openAddModal, setOpenAddModal] = useState(false);
|
|
||||||
const [openDeployModal, setOpenDeployModal] = useState<{
|
const [openDeployModal, setOpenDeployModal] = useState<{
|
||||||
show: boolean;
|
show: boolean;
|
||||||
width: number | string;
|
width: number | string;
|
||||||
@@ -183,7 +185,6 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
isGGUF: false,
|
isGGUF: false,
|
||||||
source: modelSourceMap.huggingface_value as SourceType
|
source: modelSourceMap.huggingface_value as SourceType
|
||||||
});
|
});
|
||||||
const currentData = useRef<ListItem>({} as ListItem);
|
|
||||||
const [currentInstance, setCurrentInstance] = useState<{
|
const [currentInstance, setCurrentInstance] = useState<{
|
||||||
url: string;
|
url: string;
|
||||||
status: string;
|
status: string;
|
||||||
@@ -194,17 +195,6 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
url: '',
|
url: '',
|
||||||
status: ''
|
status: ''
|
||||||
});
|
});
|
||||||
const [openAccessControlModal, setOpenAccessControlModal] = useState<{
|
|
||||||
open: boolean;
|
|
||||||
currentData: ListItem | null;
|
|
||||||
title: string;
|
|
||||||
action: PageActionType;
|
|
||||||
}>({
|
|
||||||
open: false,
|
|
||||||
currentData: null,
|
|
||||||
title: '',
|
|
||||||
action: PageAction.CREATE
|
|
||||||
});
|
|
||||||
const modalRef = useRef<any>(null);
|
const modalRef = useRef<any>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -223,10 +213,6 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const setCurrentData = (data: ListItem) => {
|
|
||||||
currentData.current = data;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleOnSort = (order: TableOrder | Array<TableOrder>) => {
|
const handleOnSort = (order: TableOrder | Array<TableOrder>) => {
|
||||||
onTableSort?.(order);
|
onTableSort?.(order);
|
||||||
};
|
};
|
||||||
@@ -253,16 +239,29 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleModalOk = async (data: FormData) => {
|
const handleModalOk = async (data: FormData) => {
|
||||||
|
const currentData = openEditModalStatus.currentData;
|
||||||
try {
|
try {
|
||||||
await updateModel({
|
if (currentData.realAction === PageAction.COPY) {
|
||||||
data,
|
const modelData = await createModel({
|
||||||
id: currentData.current?.id as number
|
data
|
||||||
});
|
});
|
||||||
setOpenAddModal(false);
|
|
||||||
message.success(intl.formatMessage({ id: 'common.message.success' }));
|
if (data.replicas > 0) {
|
||||||
if (data.replicas > currentData.current?.replicas) {
|
updateExpandedRowKeys([modelData.id, ...expandedRowKeys]);
|
||||||
updateExpandedRowKeys([currentData.current?.id, ...expandedRowKeys]);
|
}
|
||||||
}
|
}
|
||||||
|
if (currentData.realAction === PageAction.EDIT) {
|
||||||
|
await updateModel({
|
||||||
|
data,
|
||||||
|
id: currentData.row.id as number
|
||||||
|
});
|
||||||
|
|
||||||
|
if (data.replicas > currentData.row.replicas) {
|
||||||
|
updateExpandedRowKeys([currentData.row.id, ...expandedRowKeys]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closeEditModal();
|
||||||
|
message.success(intl.formatMessage({ id: 'common.message.success' }));
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
handleSearch();
|
handleSearch();
|
||||||
}, 150);
|
}, 150);
|
||||||
@@ -271,7 +270,7 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleModalCancel = useCallback(() => {
|
const handleModalCancel = useCallback(() => {
|
||||||
setOpenAddModal(false);
|
closeEditModal();
|
||||||
restoreScrollHeight();
|
restoreScrollHeight();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -282,29 +281,28 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCreateModel = useCallback(
|
const refreshListStatus = (modelData: ListItem) => {
|
||||||
async (data: FormData) => {
|
setTimeout(() => {
|
||||||
try {
|
updateExpandedRowKeys([modelData.id, ...expandedRowKeys]);
|
||||||
console.log('data:', data, openDeployModal);
|
}, 300);
|
||||||
|
message.success(intl.formatMessage({ id: 'common.message.success' }));
|
||||||
|
setTimeout(() => {
|
||||||
|
handleSearch?.();
|
||||||
|
}, 150);
|
||||||
|
};
|
||||||
|
|
||||||
const modelData = await createModel({
|
const handleCreateModel = async (data: FormData) => {
|
||||||
data
|
try {
|
||||||
});
|
const modelData = await createModel({
|
||||||
setOpenDeployModal({
|
data
|
||||||
...openDeployModal,
|
});
|
||||||
show: false
|
setOpenDeployModal({
|
||||||
});
|
...openDeployModal,
|
||||||
setTimeout(() => {
|
show: false
|
||||||
updateExpandedRowKeys([modelData.id, ...expandedRowKeys]);
|
});
|
||||||
}, 300);
|
refreshListStatus(modelData);
|
||||||
message.success(intl.formatMessage({ id: 'common.message.success' }));
|
} catch (error) {}
|
||||||
setTimeout(() => {
|
};
|
||||||
handleSearch?.();
|
|
||||||
}, 150);
|
|
||||||
} catch (error) {}
|
|
||||||
},
|
|
||||||
[openDeployModal]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleLogModalCancel = useCallback(() => {
|
const handleLogModalCancel = useCallback(() => {
|
||||||
setOpenLogModal(false);
|
setOpenLogModal(false);
|
||||||
@@ -400,28 +398,23 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
return `${MODELS_API}/${params.id}/instances`;
|
return `${MODELS_API}/${params.id}/instances`;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleEdit = async (row: ListItem) => {
|
const handleEdit = async (row: ListItem, realAction: PageActionType) => {
|
||||||
const initialValues = generateFormValues(row, []);
|
const initialValues = generateFormValues(row, []);
|
||||||
setUpdateFormInitials({
|
if (realAction === PageAction.EDIT) {
|
||||||
data: initialValues,
|
openEditModal(initialValues, row);
|
||||||
isGGUF: false
|
} else if (realAction === PageAction.COPY) {
|
||||||
});
|
openDuplicateModal(initialValues, row);
|
||||||
setCurrentData(row);
|
}
|
||||||
setOpenAddModal(true);
|
|
||||||
saveScrollHeight();
|
saveScrollHeight();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleViewAPIInfo = useCallback((row: ListItem) => {
|
|
||||||
setAPIAccessInfo({
|
|
||||||
show: true,
|
|
||||||
data: row
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleSelect = useMemoizedFn(async (val: any, row: ListItem) => {
|
const handleSelect = useMemoizedFn(async (val: any, row: ListItem) => {
|
||||||
try {
|
try {
|
||||||
if (val === 'edit') {
|
if (val === 'edit') {
|
||||||
handleEdit(row);
|
handleEdit(row, PageAction.EDIT);
|
||||||
|
}
|
||||||
|
if (val === 'copy') {
|
||||||
|
handleEdit(row, PageAction.COPY);
|
||||||
}
|
}
|
||||||
if (val === 'delete') {
|
if (val === 'delete') {
|
||||||
handleDelete(row);
|
handleDelete(row);
|
||||||
@@ -433,10 +426,6 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
onStart?.();
|
onStart?.();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (val === 'api') {
|
|
||||||
handleViewAPIInfo(row);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (val === 'stop') {
|
if (val === 'stop') {
|
||||||
modalRef.current?.show({
|
modalRef.current?.show({
|
||||||
content: 'models.instances',
|
content: 'models.instances',
|
||||||
@@ -450,13 +439,16 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (val === 'chat') {
|
||||||
|
const targetRoute = targetList.find(
|
||||||
|
(target) =>
|
||||||
|
target.model_id === row.id &&
|
||||||
|
target.state === TargetStatusValueMap.Active
|
||||||
|
);
|
||||||
|
|
||||||
if (val === 'accessControl') {
|
handleOpenPlayGround({
|
||||||
setOpenAccessControlModal({
|
categories: row.categories || [],
|
||||||
title: intl.formatMessage({ id: 'models.button.accessSettings' }),
|
name: targetRoute?.route_name || ''
|
||||||
action: PageAction.EDIT,
|
|
||||||
currentData: row,
|
|
||||||
open: true
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -551,7 +543,8 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
return {
|
return {
|
||||||
handleSelect,
|
handleSelect,
|
||||||
clusterList,
|
clusterList,
|
||||||
sortOrder
|
sortOrder,
|
||||||
|
targetList: targetList
|
||||||
};
|
};
|
||||||
}, [handleSelect, clusterList, sortOrder]);
|
}, [handleSelect, clusterList, sortOrder]);
|
||||||
|
|
||||||
@@ -565,14 +558,6 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleCancelAccessControl = () => {
|
|
||||||
setOpenAccessControlModal({
|
|
||||||
...openAccessControlModal,
|
|
||||||
currentData: null,
|
|
||||||
open: false
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const { noResourceResult } = useNoResourceResult({
|
const { noResourceResult } = useNoResourceResult({
|
||||||
loadend: loadend,
|
loadend: loadend,
|
||||||
loading: loading,
|
loading: loading,
|
||||||
@@ -735,10 +720,10 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
></SealTable>
|
></SealTable>
|
||||||
</PageBox>
|
</PageBox>
|
||||||
<UpdateModelModal
|
<UpdateModelModal
|
||||||
open={openAddModal}
|
open={openEditModalStatus.open}
|
||||||
action={PageAction.EDIT}
|
action={openEditModalStatus.action}
|
||||||
title={intl.formatMessage({ id: 'models.title.edit' })}
|
title={openEditModalStatus.title}
|
||||||
updateFormInitials={updateFormInitials}
|
currentData={openEditModalStatus.currentData}
|
||||||
clusterList={clusterList}
|
clusterList={clusterList}
|
||||||
onCancel={handleModalCancel}
|
onCancel={handleModalCancel}
|
||||||
onOk={handleModalOk}
|
onOk={handleModalOk}
|
||||||
@@ -765,23 +750,6 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
onCancel={handleLogModalCancel}
|
onCancel={handleLogModalCancel}
|
||||||
></ViewLogsModal>
|
></ViewLogsModal>
|
||||||
<DeleteModal ref={modalRef}></DeleteModal>
|
<DeleteModal ref={modalRef}></DeleteModal>
|
||||||
<APIAccessInfoModal
|
|
||||||
open={apiAccessInfo.show}
|
|
||||||
data={apiAccessInfo.data}
|
|
||||||
onClose={() => {
|
|
||||||
setAPIAccessInfo({
|
|
||||||
...apiAccessInfo,
|
|
||||||
show: false
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
></APIAccessInfoModal>
|
|
||||||
<AccessControlModal
|
|
||||||
onCancel={handleCancelAccessControl}
|
|
||||||
title={openAccessControlModal.title}
|
|
||||||
open={openAccessControlModal.open}
|
|
||||||
currentData={openAccessControlModal.currentData}
|
|
||||||
action={openAccessControlModal.action}
|
|
||||||
></AccessControlModal>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import ModalFooter from '@/components/modal-footer';
|
import ModalFooter from '@/components/modal-footer';
|
||||||
import GSDrawer from '@/components/scroller-modal/gs-drawer';
|
import GSDrawer from '@/components/scroller-modal/gs-drawer';
|
||||||
|
import { PageAction } from '@/config';
|
||||||
import { PageActionType } from '@/config/types';
|
import { PageActionType } from '@/config/types';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Button } from 'antd';
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import React, { useEffect, useMemo, useRef } from 'react';
|
import React, { useEffect, useRef } from 'react';
|
||||||
import ColumnWrapper from '../../_components/column-wrapper';
|
import ColumnWrapper from '../../_components/column-wrapper';
|
||||||
import {
|
import {
|
||||||
DeployFormKeyMap,
|
DeployFormKeyMap,
|
||||||
@@ -22,9 +22,10 @@ type AddModalProps = {
|
|||||||
title: string;
|
title: string;
|
||||||
action: PageActionType;
|
action: PageActionType;
|
||||||
open: boolean;
|
open: boolean;
|
||||||
updateFormInitials: {
|
currentData: {
|
||||||
data: FormData;
|
data: FormData;
|
||||||
isGGUF: boolean;
|
isGGUF: boolean;
|
||||||
|
realAction?: PageActionType;
|
||||||
};
|
};
|
||||||
clusterList: Global.BaseOption<
|
clusterList: Global.BaseOption<
|
||||||
number,
|
number,
|
||||||
@@ -48,7 +49,7 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
|
|||||||
onOk,
|
onOk,
|
||||||
onCancel,
|
onCancel,
|
||||||
clusterList,
|
clusterList,
|
||||||
updateFormInitials: { isGGUF, data: formData }
|
currentData: { isGGUF, data: formData, realAction }
|
||||||
} = props || {};
|
} = props || {};
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const {
|
const {
|
||||||
@@ -198,14 +199,6 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
|
|||||||
onCancel?.();
|
onCancel?.();
|
||||||
};
|
};
|
||||||
|
|
||||||
const showExtraButton = useMemo(() => {
|
|
||||||
return (
|
|
||||||
warningStatus.show &&
|
|
||||||
warningStatus.type !== 'success' &&
|
|
||||||
!warningStatus.isDefault
|
|
||||||
);
|
|
||||||
}, [warningStatus.show, warningStatus.type, warningStatus.isDefault]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const initGPUSelector = async () => {
|
const initGPUSelector = async () => {
|
||||||
const gpuOptions = await formRef.current?.getGPUOptionList({
|
const gpuOptions = await formRef.current?.getGPUOptionList({
|
||||||
@@ -256,31 +249,23 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
|
|||||||
}}
|
}}
|
||||||
footer={
|
footer={
|
||||||
<>
|
<>
|
||||||
<CompatibilityAlert
|
{realAction === PageAction.EDIT && (
|
||||||
showClose={false}
|
<CompatibilityAlert
|
||||||
onClose={() => {
|
showClose={false}
|
||||||
setWarningStatus({
|
onClose={() => {
|
||||||
show: false,
|
setWarningStatus({
|
||||||
message: ''
|
show: false,
|
||||||
});
|
message: ''
|
||||||
}}
|
});
|
||||||
warningStatus={warningStatus}
|
}}
|
||||||
contentStyle={{ paddingInline: 0 }}
|
warningStatus={warningStatus}
|
||||||
></CompatibilityAlert>
|
contentStyle={{ paddingInline: 0 }}
|
||||||
|
></CompatibilityAlert>
|
||||||
|
)}
|
||||||
<ModalFooter
|
<ModalFooter
|
||||||
style={ModalFooterStyle}
|
style={ModalFooterStyle}
|
||||||
onCancel={onCancel}
|
onCancel={onCancel}
|
||||||
onOk={handleSumit}
|
onOk={handleSumit}
|
||||||
showOkBtn={!showExtraButton}
|
|
||||||
extra={
|
|
||||||
showExtraButton && (
|
|
||||||
<Button type="primary" onClick={handleSubmitAnyway}>
|
|
||||||
{intl.formatMessage({
|
|
||||||
id: 'models.form.submit.anyway'
|
|
||||||
})}
|
|
||||||
</Button>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
></ModalFooter>
|
></ModalFooter>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,16 +39,21 @@ export const ActionList: ActionItem[] = [
|
|||||||
key: 'edit',
|
key: 'edit',
|
||||||
icon: icons.EditOutlined
|
icon: icons.EditOutlined
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'models.openinplayground',
|
||||||
|
key: 'chat',
|
||||||
|
icon: icons.ExperimentOutlined
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'copy',
|
||||||
|
label: 'common.button.duplicate',
|
||||||
|
icon: icons.CopyOutlined
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: 'common.button.start',
|
label: 'common.button.start',
|
||||||
key: 'start',
|
key: 'start',
|
||||||
icon: icons.Play
|
icon: icons.Play
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: 'models.table.button.apiAccessInfo',
|
|
||||||
key: 'api',
|
|
||||||
icon: icons.ApiOutlined
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: 'common.button.stop',
|
label: 'common.button.stop',
|
||||||
key: 'stop',
|
key: 'stop',
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
import { PageAction } from '@/config';
|
||||||
|
import { PageActionType } from '@/config/types';
|
||||||
|
import { useIntl } from '@umijs/max';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { ListItem } from '../config/types';
|
||||||
|
|
||||||
|
const useEditDeployment = () => {
|
||||||
|
const intl = useIntl();
|
||||||
|
const [openModalStatus, setOpenModalStatus] = useState<{
|
||||||
|
open: boolean;
|
||||||
|
action: PageActionType;
|
||||||
|
currentData: {
|
||||||
|
isGGUF: boolean;
|
||||||
|
data: any; // for form data
|
||||||
|
row: ListItem;
|
||||||
|
realAction?: PageActionType; // added action here for copy action
|
||||||
|
};
|
||||||
|
title: string;
|
||||||
|
}>({
|
||||||
|
open: false,
|
||||||
|
action: PageAction.EDIT,
|
||||||
|
currentData: {
|
||||||
|
isGGUF: false,
|
||||||
|
data: {},
|
||||||
|
row: {} as ListItem
|
||||||
|
},
|
||||||
|
title: ''
|
||||||
|
});
|
||||||
|
|
||||||
|
const openEditModal = (formData: any, row: ListItem) => {
|
||||||
|
setOpenModalStatus({
|
||||||
|
open: true,
|
||||||
|
action: PageAction.EDIT,
|
||||||
|
currentData: {
|
||||||
|
isGGUF: false,
|
||||||
|
data: formData,
|
||||||
|
row: row
|
||||||
|
},
|
||||||
|
title: intl.formatMessage({ id: 'models.title.edit' })
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const openDuplicateModal = (formData: any, row: ListItem) => {
|
||||||
|
setOpenModalStatus({
|
||||||
|
open: true,
|
||||||
|
action: PageAction.EDIT,
|
||||||
|
currentData: {
|
||||||
|
isGGUF: false,
|
||||||
|
data: {
|
||||||
|
...formData,
|
||||||
|
name: `${formData.name}-copy`
|
||||||
|
},
|
||||||
|
row: row,
|
||||||
|
realAction: PageAction.COPY
|
||||||
|
},
|
||||||
|
title: intl.formatMessage({ id: 'models.title.duplicate' })
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeModal = () => {
|
||||||
|
setOpenModalStatus({
|
||||||
|
open: false,
|
||||||
|
action: PageAction.EDIT,
|
||||||
|
currentData: {
|
||||||
|
isGGUF: false,
|
||||||
|
data: {},
|
||||||
|
row: {} as ListItem
|
||||||
|
},
|
||||||
|
title: ''
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
openEditModalStatus: openModalStatus,
|
||||||
|
setOpenEditModalStatus: setOpenModalStatus,
|
||||||
|
openEditModal: openEditModal,
|
||||||
|
openDuplicateModal: openDuplicateModal,
|
||||||
|
closeEditModal: closeModal
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useEditDeployment;
|
||||||
@@ -3,8 +3,10 @@ import AutoTooltip from '@/components/auto-tooltip';
|
|||||||
import DropdownButtons from '@/components/drop-down-buttons';
|
import DropdownButtons from '@/components/drop-down-buttons';
|
||||||
import { SealColumnProps } from '@/components/seal-table/types';
|
import { SealColumnProps } from '@/components/seal-table/types';
|
||||||
import { OPENAI_COMPATIBLE, tableSorter } from '@/config/settings';
|
import { OPENAI_COMPATIBLE, tableSorter } from '@/config/settings';
|
||||||
|
import { TargetStatusValueMap } from '@/pages/model-routes/config';
|
||||||
import { QuestionCircleOutlined } from '@ant-design/icons';
|
import { QuestionCircleOutlined } from '@ant-design/icons';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
|
import { useMemoizedFn } from 'ahooks';
|
||||||
import { Tooltip } from 'antd';
|
import { Tooltip } from 'antd';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
@@ -13,24 +15,6 @@ import ModelTag from '../../_components/model-tag';
|
|||||||
import { ActionList, generateSource } from '../config/button-actions';
|
import { ActionList, generateSource } from '../config/button-actions';
|
||||||
import { ListItem } from '../config/types';
|
import { ListItem } from '../config/types';
|
||||||
|
|
||||||
const setModelActionList = (record: any) => {
|
|
||||||
return _.filter(ActionList, (action: any) => {
|
|
||||||
if (action.key === 'chat' || action.key === 'api') {
|
|
||||||
return record.ready_replicas > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action.key === 'start') {
|
|
||||||
return record.replicas === 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action.key === 'stop') {
|
|
||||||
return record.replicas > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
interface ModelsColumnsHookProps {
|
interface ModelsColumnsHookProps {
|
||||||
handleSelect: (val: string, record: ListItem) => void;
|
handleSelect: (val: string, record: ListItem) => void;
|
||||||
sortOrder: string[];
|
sortOrder: string[];
|
||||||
@@ -43,10 +27,36 @@ interface ModelsColumnsHookProps {
|
|||||||
const useModelsColumns = ({
|
const useModelsColumns = ({
|
||||||
handleSelect,
|
handleSelect,
|
||||||
clusterList,
|
clusterList,
|
||||||
sortOrder
|
sortOrder,
|
||||||
}: ModelsColumnsHookProps): SealColumnProps[] => {
|
targetList
|
||||||
|
}: ModelsColumnsHookProps & { targetList: any[] }): SealColumnProps[] => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const setModelActionList = useMemoizedFn((record: any) => {
|
||||||
|
return _.filter(ActionList, (action: any) => {
|
||||||
|
if (action.key === 'chat') {
|
||||||
|
return (
|
||||||
|
record.ready_replicas > 0 &&
|
||||||
|
targetList?.find(
|
||||||
|
(target) =>
|
||||||
|
target.model_id === record.id &&
|
||||||
|
target.state === TargetStatusValueMap.Active
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action.key === 'start') {
|
||||||
|
return record.replicas === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action.key === 'stop') {
|
||||||
|
return record.replicas > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
@@ -137,7 +147,7 @@ const useModelsColumns = ({
|
|||||||
key: 'operation',
|
key: 'operation',
|
||||||
dataIndex: 'operation',
|
dataIndex: 'operation',
|
||||||
span: 3,
|
span: 3,
|
||||||
render: (text, record) => (
|
render: (text: any, record: ListItem) => (
|
||||||
<DropdownButtons
|
<DropdownButtons
|
||||||
items={setModelActionList(record)}
|
items={setModelActionList(record)}
|
||||||
onSelect={(val) => handleSelect(val, record)}
|
onSelect={(val) => handleSelect(val, record)}
|
||||||
|
|||||||
@@ -36,17 +36,18 @@ export async function deleteModelRoute(id: number) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function queryRouteTargets(params: { id: number }, options?: any) {
|
export async function queryRouteTargets(
|
||||||
return request<Global.PageResponse<RouteTarget>>(
|
params: { id?: number },
|
||||||
`${MODEL_ROUTE_TARGETS}?route_id=${params.id}`,
|
options?: any
|
||||||
{
|
) {
|
||||||
method: 'GET',
|
return request<Global.PageResponse<RouteTarget>>(`${MODEL_ROUTE_TARGETS}`, {
|
||||||
params: {
|
method: 'GET',
|
||||||
page: -1
|
params: {
|
||||||
},
|
route_id: params.id,
|
||||||
cancelToken: options?.token
|
page: -1
|
||||||
}
|
},
|
||||||
);
|
cancelToken: options?.token
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteModelRouteTarget(id: number) {
|
export async function deleteModelRouteTarget(id: number) {
|
||||||
|
|||||||
@@ -29,6 +29,11 @@ export const rowActionList = [
|
|||||||
key: 'chat',
|
key: 'chat',
|
||||||
icon: icons.ExperimentOutlined
|
icon: icons.ExperimentOutlined
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'models.table.button.apiAccessInfo',
|
||||||
|
key: 'api',
|
||||||
|
icon: icons.ApiOutlined
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: 'models.button.accessSettings',
|
label: 'models.button.accessSettings',
|
||||||
key: 'accessControl',
|
key: 'accessControl',
|
||||||
|
|||||||
@@ -38,13 +38,10 @@ export interface RouteTarget {
|
|||||||
id: number;
|
id: number;
|
||||||
created_at: string;
|
created_at: string;
|
||||||
updated_at: string;
|
updated_at: string;
|
||||||
deleted_at: string;
|
weight: number;
|
||||||
provider_model_name: string;
|
|
||||||
weight: number | null;
|
|
||||||
model_id: number;
|
model_id: number;
|
||||||
provider_id: number;
|
|
||||||
name: string;
|
name: string;
|
||||||
|
route_name: string;
|
||||||
route_id: number;
|
route_id: number;
|
||||||
state: string;
|
state: string;
|
||||||
fallback_status_codes: string[];
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,10 +13,19 @@ const Basic = () => {
|
|||||||
const { getRuleMessage } = useAppUtils();
|
const { getRuleMessage } = useAppUtils();
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Form.Item name="name" data-field="name">
|
<Form.Item
|
||||||
|
name="name"
|
||||||
|
data-field="name"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: getRuleMessage('input', 'common.table.name')
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
<SealInput.Input
|
<SealInput.Input
|
||||||
required
|
required
|
||||||
label={intl.formatMessage({ id: 'models.table.name' })}
|
label={intl.formatMessage({ id: 'common.table.name' })}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ const useAccessColumns = (
|
|||||||
|
|
||||||
const filterActions = (record: RouteItem) => {
|
const filterActions = (record: RouteItem) => {
|
||||||
return rowActionList.filter((action) => {
|
return rowActionList.filter((action) => {
|
||||||
if (action.key === 'chat') {
|
if (action.key === 'chat' || action.key === 'api') {
|
||||||
return record.ready_targets > 0;
|
return record.ready_targets > 0;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
const useViewApIInfo = () => {
|
||||||
|
const [apiAccessInfo, setAPIAccessInfo] = useState<any>({
|
||||||
|
show: false,
|
||||||
|
data: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
const openViewAPIInfo = (row: any) => {
|
||||||
|
setAPIAccessInfo({
|
||||||
|
show: true,
|
||||||
|
data: row
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeViewAPIInfo = () => {
|
||||||
|
setAPIAccessInfo({
|
||||||
|
show: false,
|
||||||
|
data: {}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
apiAccessInfo,
|
||||||
|
openViewAPIInfo,
|
||||||
|
closeViewAPIInfo
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useViewApIInfo;
|
||||||
@@ -10,6 +10,7 @@ import { TABLE_SORT_DIRECTIONS } from '@/config/settings';
|
|||||||
import useExpandedRowKeys from '@/hooks/use-expanded-row-keys';
|
import useExpandedRowKeys from '@/hooks/use-expanded-row-keys';
|
||||||
import useTableFetch from '@/hooks/use-table-fetch';
|
import useTableFetch from '@/hooks/use-table-fetch';
|
||||||
import useWatchList from '@/hooks/use-watch-list';
|
import useWatchList from '@/hooks/use-watch-list';
|
||||||
|
import APIAccessInfoModal from '@/pages/llmodels/components/api-access-info';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { useMemoizedFn } from 'ahooks';
|
import { useMemoizedFn } from 'ahooks';
|
||||||
import { message } from 'antd';
|
import { message } from 'antd';
|
||||||
@@ -39,6 +40,7 @@ import useCreateRoute from './hooks/use-create-route';
|
|||||||
import useOpenPlayground from './hooks/use-open-playground';
|
import useOpenPlayground from './hooks/use-open-playground';
|
||||||
import useRoutesColumns from './hooks/use-routes-columns';
|
import useRoutesColumns from './hooks/use-routes-columns';
|
||||||
import useTargetSourceModels from './hooks/use-target-source-models';
|
import useTargetSourceModels from './hooks/use-target-source-models';
|
||||||
|
import useViewApIInfo from './hooks/use-view-api-info';
|
||||||
|
|
||||||
const ModelRoutes: React.FC = () => {
|
const ModelRoutes: React.FC = () => {
|
||||||
const {
|
const {
|
||||||
@@ -75,6 +77,7 @@ const ModelRoutes: React.FC = () => {
|
|||||||
} = useAccessControl();
|
} = useAccessControl();
|
||||||
const { sourceModels, fetchSourceModels } = useTargetSourceModels();
|
const { sourceModels, fetchSourceModels } = useTargetSourceModels();
|
||||||
const { handleOpenPlayGround } = useOpenPlayground();
|
const { handleOpenPlayGround } = useOpenPlayground();
|
||||||
|
const { apiAccessInfo, openViewAPIInfo, closeViewAPIInfo } = useViewApIInfo();
|
||||||
const [modelList, setModelsList] = useState<Global.BaseOption<number>[]>([]);
|
const [modelList, setModelsList] = useState<Global.BaseOption<number>[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -149,6 +152,8 @@ const ModelRoutes: React.FC = () => {
|
|||||||
);
|
);
|
||||||
} else if (val === 'chat') {
|
} else if (val === 'chat') {
|
||||||
handleOpenPlayGround(row);
|
handleOpenPlayGround(row);
|
||||||
|
} else if (val === 'api') {
|
||||||
|
openViewAPIInfo(row);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -316,6 +321,11 @@ const ModelRoutes: React.FC = () => {
|
|||||||
currentData={openAccessControlModalStatus.currentData}
|
currentData={openAccessControlModalStatus.currentData}
|
||||||
action={openAccessControlModalStatus.action}
|
action={openAccessControlModalStatus.action}
|
||||||
></AccessControlModal>
|
></AccessControlModal>
|
||||||
|
<APIAccessInfoModal
|
||||||
|
open={apiAccessInfo.show}
|
||||||
|
data={apiAccessInfo.data}
|
||||||
|
onClose={closeViewAPIInfo}
|
||||||
|
></APIAccessInfoModal>
|
||||||
<DeleteModal ref={modalRef}></DeleteModal>
|
<DeleteModal ref={modalRef}></DeleteModal>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { useQueryDataList } from '@/hooks/use-query-data-list';
|
||||||
|
import { queryRouteTargets } from '../apis';
|
||||||
|
import { RouteTarget as ListItem } from '../config/types';
|
||||||
|
|
||||||
|
export const useQueryRouteTargets = (optons?: {
|
||||||
|
getLabel?: (item: ListItem) => string;
|
||||||
|
getValue?: (item: ListItem) => any;
|
||||||
|
}) => {
|
||||||
|
const { dataList, loading, fetchData, cancelRequest } =
|
||||||
|
useQueryDataList<ListItem>({
|
||||||
|
key: 'routeTargets',
|
||||||
|
fetchList: queryRouteTargets
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
dataList,
|
||||||
|
loading,
|
||||||
|
fetchData,
|
||||||
|
cancelRequest
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useQueryRouteTargets;
|
||||||
@@ -179,14 +179,13 @@ const generateEnvArgs = (params: any) => {
|
|||||||
|
|
||||||
// concat the args, the args is a key-value
|
// concat the args, the args is a key-value
|
||||||
const generateExtraArgs = (params: any) => {
|
const generateExtraArgs = (params: any) => {
|
||||||
const args = params.registrationInfo?.args || {};
|
const args = params.registrationInfo?.args || [];
|
||||||
const argsList = Object.entries(args);
|
if (args.length === 0) {
|
||||||
if (argsList.length === 0) {
|
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
let argsStr = '';
|
let argsStr = '';
|
||||||
argsList.forEach(([key, value]) => {
|
args.forEach((item: string[]) => {
|
||||||
argsStr += `${key} ${_.isBoolean(value) ? value : value || ''} \\\n `;
|
argsStr += `${item[0]} ${_.isBoolean(item[1]) ? item[1] : item[1] || ''} \\\n `;
|
||||||
});
|
});
|
||||||
return argsStr;
|
return argsStr;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user