diff --git a/config/routes.ts b/config/routes.ts
index 6b1fbb2c..ee7a95b4 100644
--- a/config/routes.ts
+++ b/config/routes.ts
@@ -86,14 +86,14 @@ export default [
redirect: '/models/deployments'
},
{
- name: 'routes',
- path: '/models/routes',
- key: 'routes',
- icon: 'icon-captive_portal',
- selectedIcon: 'icon-captive_portal',
- defaultIcon: 'icon-captive_portal',
+ name: 'modelCatalog',
+ path: '/models/catalog',
+ key: 'modelsCatalog',
+ icon: 'icon-layers',
+ selectedIcon: 'icon-layers-filled',
+ defaultIcon: 'icon-layers',
access: 'canSeeAdmin',
- component: './model-routes/index'
+ component: './llmodels/catalog'
},
{
name: 'deployment',
@@ -106,14 +106,14 @@ export default [
component: './llmodels/index'
},
{
- name: 'modelCatalog',
- path: '/models/catalog',
- key: 'modelsCatalog',
- icon: 'icon-layers',
- selectedIcon: 'icon-layers-filled',
- defaultIcon: 'icon-layers',
+ name: 'routes',
+ path: '/models/routes',
+ key: 'routes',
+ icon: 'icon-captive_portal',
+ selectedIcon: 'icon-captive_portal',
+ defaultIcon: 'icon-captive_portal',
access: 'canSeeAdmin',
- component: './llmodels/catalog'
+ component: './model-routes/index'
},
{
name: 'providers',
diff --git a/src/components/footer/index.tsx b/src/components/footer/index.tsx
index e69d6210..48acfc50 100644
--- a/src/components/footer/index.tsx
+++ b/src/components/footer/index.tsx
@@ -3,7 +3,7 @@ import { getAtomStorage } from '@/atoms/utils';
import VersionInfo, { modalConfig } from '@/components/version-info';
import externalLinks from '@/constants/external-links';
import { useIntl } from '@umijs/max';
-import { Button, Divider, Modal } from 'antd';
+import { Button, Divider, Modal, Typography } from 'antd';
import { createStyles } from 'antd-style';
import styled from 'styled-components';
@@ -54,7 +54,13 @@ const Footer: React.FC = () => {
©
{new Date().getFullYear()}
- {intl.formatMessage({ id: 'settings.company' })}
+
+ {intl.formatMessage({ id: 'settings.company' })}
+
- )
- }
>
>
}
diff --git a/src/pages/llmodels/config/button-actions.ts b/src/pages/llmodels/config/button-actions.ts
index a4567541..c3685c45 100644
--- a/src/pages/llmodels/config/button-actions.ts
+++ b/src/pages/llmodels/config/button-actions.ts
@@ -39,16 +39,21 @@ export const ActionList: ActionItem[] = [
key: 'edit',
icon: icons.EditOutlined
},
+ {
+ label: 'models.openinplayground',
+ key: 'chat',
+ icon: icons.ExperimentOutlined
+ },
+ {
+ key: 'copy',
+ label: 'common.button.duplicate',
+ icon: icons.CopyOutlined
+ },
{
label: 'common.button.start',
key: 'start',
icon: icons.Play
},
- {
- label: 'models.table.button.apiAccessInfo',
- key: 'api',
- icon: icons.ApiOutlined
- },
{
label: 'common.button.stop',
key: 'stop',
diff --git a/src/pages/llmodels/hooks/use-edit-deployment.ts b/src/pages/llmodels/hooks/use-edit-deployment.ts
new file mode 100644
index 00000000..8a368cbb
--- /dev/null
+++ b/src/pages/llmodels/hooks/use-edit-deployment.ts
@@ -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;
diff --git a/src/pages/llmodels/hooks/use-models-columns.tsx b/src/pages/llmodels/hooks/use-models-columns.tsx
index df167913..05912309 100644
--- a/src/pages/llmodels/hooks/use-models-columns.tsx
+++ b/src/pages/llmodels/hooks/use-models-columns.tsx
@@ -3,8 +3,10 @@ import AutoTooltip from '@/components/auto-tooltip';
import DropdownButtons from '@/components/drop-down-buttons';
import { SealColumnProps } from '@/components/seal-table/types';
import { OPENAI_COMPATIBLE, tableSorter } from '@/config/settings';
+import { TargetStatusValueMap } from '@/pages/model-routes/config';
import { QuestionCircleOutlined } from '@ant-design/icons';
import { useIntl } from '@umijs/max';
+import { useMemoizedFn } from 'ahooks';
import { Tooltip } from 'antd';
import dayjs from 'dayjs';
import _ from 'lodash';
@@ -13,24 +15,6 @@ import ModelTag from '../../_components/model-tag';
import { ActionList, generateSource } from '../config/button-actions';
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 {
handleSelect: (val: string, record: ListItem) => void;
sortOrder: string[];
@@ -43,10 +27,36 @@ interface ModelsColumnsHookProps {
const useModelsColumns = ({
handleSelect,
clusterList,
- sortOrder
-}: ModelsColumnsHookProps): SealColumnProps[] => {
+ sortOrder,
+ targetList
+}: ModelsColumnsHookProps & { targetList: any[] }): SealColumnProps[] => {
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 [
{
@@ -137,7 +147,7 @@ const useModelsColumns = ({
key: 'operation',
dataIndex: 'operation',
span: 3,
- render: (text, record) => (
+ render: (text: any, record: ListItem) => (
handleSelect(val, record)}
diff --git a/src/pages/model-routes/apis/index.ts b/src/pages/model-routes/apis/index.ts
index aeba1000..ff759006 100644
--- a/src/pages/model-routes/apis/index.ts
+++ b/src/pages/model-routes/apis/index.ts
@@ -36,17 +36,18 @@ export async function deleteModelRoute(id: number) {
});
}
-export async function queryRouteTargets(params: { id: number }, options?: any) {
- return request>(
- `${MODEL_ROUTE_TARGETS}?route_id=${params.id}`,
- {
- method: 'GET',
- params: {
- page: -1
- },
- cancelToken: options?.token
- }
- );
+export async function queryRouteTargets(
+ params: { id?: number },
+ options?: any
+) {
+ return request>(`${MODEL_ROUTE_TARGETS}`, {
+ method: 'GET',
+ params: {
+ route_id: params.id,
+ page: -1
+ },
+ cancelToken: options?.token
+ });
}
export async function deleteModelRouteTarget(id: number) {
diff --git a/src/pages/model-routes/config/index.ts b/src/pages/model-routes/config/index.ts
index db6a4a52..e66067be 100644
--- a/src/pages/model-routes/config/index.ts
+++ b/src/pages/model-routes/config/index.ts
@@ -29,6 +29,11 @@ export const rowActionList = [
key: 'chat',
icon: icons.ExperimentOutlined
},
+ {
+ label: 'models.table.button.apiAccessInfo',
+ key: 'api',
+ icon: icons.ApiOutlined
+ },
{
label: 'models.button.accessSettings',
key: 'accessControl',
diff --git a/src/pages/model-routes/config/types.ts b/src/pages/model-routes/config/types.ts
index c114268a..ad028542 100644
--- a/src/pages/model-routes/config/types.ts
+++ b/src/pages/model-routes/config/types.ts
@@ -38,13 +38,10 @@ export interface RouteTarget {
id: number;
created_at: string;
updated_at: string;
- deleted_at: string;
- provider_model_name: string;
- weight: number | null;
+ weight: number;
model_id: number;
- provider_id: number;
name: string;
+ route_name: string;
route_id: number;
state: string;
- fallback_status_codes: string[];
}
diff --git a/src/pages/model-routes/forms/basic.tsx b/src/pages/model-routes/forms/basic.tsx
index ee1520b5..646b3eea 100644
--- a/src/pages/model-routes/forms/basic.tsx
+++ b/src/pages/model-routes/forms/basic.tsx
@@ -13,10 +13,19 @@ const Basic = () => {
const { getRuleMessage } = useAppUtils();
return (
<>
-
+
{
return rowActionList.filter((action) => {
- if (action.key === 'chat') {
+ if (action.key === 'chat' || action.key === 'api') {
return record.ready_targets > 0;
}
return true;
diff --git a/src/pages/model-routes/hooks/use-view-api-info.ts b/src/pages/model-routes/hooks/use-view-api-info.ts
new file mode 100644
index 00000000..8bee346a
--- /dev/null
+++ b/src/pages/model-routes/hooks/use-view-api-info.ts
@@ -0,0 +1,30 @@
+import { useState } from 'react';
+
+const useViewApIInfo = () => {
+ const [apiAccessInfo, setAPIAccessInfo] = useState({
+ 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;
diff --git a/src/pages/model-routes/index.tsx b/src/pages/model-routes/index.tsx
index c7f954e0..19d312b0 100644
--- a/src/pages/model-routes/index.tsx
+++ b/src/pages/model-routes/index.tsx
@@ -10,6 +10,7 @@ import { TABLE_SORT_DIRECTIONS } from '@/config/settings';
import useExpandedRowKeys from '@/hooks/use-expanded-row-keys';
import useTableFetch from '@/hooks/use-table-fetch';
import useWatchList from '@/hooks/use-watch-list';
+import APIAccessInfoModal from '@/pages/llmodels/components/api-access-info';
import { useIntl } from '@umijs/max';
import { useMemoizedFn } from 'ahooks';
import { message } from 'antd';
@@ -39,6 +40,7 @@ import useCreateRoute from './hooks/use-create-route';
import useOpenPlayground from './hooks/use-open-playground';
import useRoutesColumns from './hooks/use-routes-columns';
import useTargetSourceModels from './hooks/use-target-source-models';
+import useViewApIInfo from './hooks/use-view-api-info';
const ModelRoutes: React.FC = () => {
const {
@@ -75,6 +77,7 @@ const ModelRoutes: React.FC = () => {
} = useAccessControl();
const { sourceModels, fetchSourceModels } = useTargetSourceModels();
const { handleOpenPlayGround } = useOpenPlayground();
+ const { apiAccessInfo, openViewAPIInfo, closeViewAPIInfo } = useViewApIInfo();
const [modelList, setModelsList] = useState[]>([]);
useEffect(() => {
@@ -149,6 +152,8 @@ const ModelRoutes: React.FC = () => {
);
} else if (val === 'chat') {
handleOpenPlayGround(row);
+ } else if (val === 'api') {
+ openViewAPIInfo(row);
}
});
@@ -316,6 +321,11 @@ const ModelRoutes: React.FC = () => {
currentData={openAccessControlModalStatus.currentData}
action={openAccessControlModalStatus.action}
>
+
>
);
diff --git a/src/pages/model-routes/services/use-query-targets.ts b/src/pages/model-routes/services/use-query-targets.ts
new file mode 100644
index 00000000..97ac8958
--- /dev/null
+++ b/src/pages/model-routes/services/use-query-targets.ts
@@ -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({
+ key: 'routeTargets',
+ fetchList: queryRouteTargets
+ });
+
+ return {
+ dataList,
+ loading,
+ fetchData,
+ cancelRequest
+ };
+};
+
+export default useQueryRouteTargets;
diff --git a/src/pages/resources/config/gpu-driver.ts b/src/pages/resources/config/gpu-driver.ts
index f2442fb7..8b8c17e5 100644
--- a/src/pages/resources/config/gpu-driver.ts
+++ b/src/pages/resources/config/gpu-driver.ts
@@ -179,14 +179,13 @@ const generateEnvArgs = (params: any) => {
// concat the args, the args is a key-value
const generateExtraArgs = (params: any) => {
- const args = params.registrationInfo?.args || {};
- const argsList = Object.entries(args);
- if (argsList.length === 0) {
+ const args = params.registrationInfo?.args || [];
+ if (args.length === 0) {
return '';
}
let argsStr = '';
- argsList.forEach(([key, value]) => {
- argsStr += `${key} ${_.isBoolean(value) ? value : value || ''} \\\n `;
+ args.forEach((item: string[]) => {
+ argsStr += `${item[0]} ${_.isBoolean(item[1]) ? item[1] : item[1] || ''} \\\n `;
});
return argsStr;
};