fix: access control, voices options
This commit is contained in:
@@ -4,6 +4,8 @@ import { atom, getDefaultStore } from 'jotai';
|
||||
// models expand keys: create, update , delete,
|
||||
export const modelsExpandKeysAtom = atom<string[]>([]);
|
||||
|
||||
export const modelsSessionAtom = atom<Record<string, any>>({});
|
||||
|
||||
export const requestIdAtom = atom<number>(0);
|
||||
|
||||
export const setRquestId = () => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Checkbox } from 'antd';
|
||||
import AutoComplete from '../auto-complete';
|
||||
import SealInput from '../seal-input';
|
||||
import SealSelect from '../seal-select';
|
||||
import Slider from '../seal-slider';
|
||||
@@ -12,6 +13,7 @@ const components: {
|
||||
Input: typeof SealInput.Input;
|
||||
Checkbox: typeof Checkbox;
|
||||
Switch: typeof Switch;
|
||||
AutoComplete: typeof AutoComplete;
|
||||
} = {
|
||||
InputNumber: SealInput.Number,
|
||||
Select: SealSelect,
|
||||
@@ -19,7 +21,8 @@ const components: {
|
||||
TextArea: SealInput.TextArea,
|
||||
Input: SealInput.Input,
|
||||
Checkbox: Checkbox,
|
||||
Switch: Switch
|
||||
Switch: Switch,
|
||||
AutoComplete: AutoComplete
|
||||
};
|
||||
|
||||
export default components;
|
||||
|
||||
@@ -247,5 +247,6 @@ export default {
|
||||
'models.form.gpuPerReplica.tips': 'Enter a custom number',
|
||||
'models.form.generic_proxy': 'Enable Generic Proxy',
|
||||
'models.form.generic_proxy.tips': 'Enable Generic Proxy',
|
||||
'models.form.generic_proxy.button': 'Generic Proxy'
|
||||
'models.form.generic_proxy.button': 'Generic Proxy',
|
||||
'models.accessControlModal.includeusers': 'Include Users'
|
||||
};
|
||||
|
||||
@@ -247,7 +247,8 @@ export default {
|
||||
'models.form.gpuPerReplica.tips': 'Enter a custom number',
|
||||
'models.form.generic_proxy': 'Enable Generic Proxy',
|
||||
'models.form.generic_proxy.tips': 'Enable Generic Proxy',
|
||||
'models.form.generic_proxy.button': 'Generic Proxy'
|
||||
'models.form.generic_proxy.button': 'Generic Proxy',
|
||||
'models.accessControlModal.includeusers': 'Include Users'
|
||||
};
|
||||
|
||||
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
||||
@@ -322,6 +323,7 @@ export default {
|
||||
// 52. 'models.form.gpuPerReplica.tips': 'Enter a custom number',
|
||||
// 53. 'models.form.generic_proxy': 'Enable Generic Proxy',
|
||||
// 54. 'models.form.generic_proxy.tips': 'Enable Generic Proxy',
|
||||
// 55. 'models.form.generic_proxy.button': 'Generic Proxy'
|
||||
// 55. 'models.form.generic_proxy.button': 'Generic Proxy',
|
||||
// 56. 'models.accessControlModal.includeusers': 'Include Users'
|
||||
|
||||
// ========== End of To-Do List ==========
|
||||
|
||||
@@ -248,7 +248,8 @@ export default {
|
||||
'models.form.gpuPerReplica.tips': 'Enter a custom number',
|
||||
'models.form.generic_proxy': 'Enable Generic Proxy',
|
||||
'models.form.generic_proxy.tips': 'Enable Generic Proxy',
|
||||
'models.form.generic_proxy.button': 'Generic Proxy'
|
||||
'models.form.generic_proxy.button': 'Generic Proxy',
|
||||
'models.accessControlModal.includeusers': 'Include Users'
|
||||
};
|
||||
|
||||
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
||||
@@ -256,5 +257,6 @@ export default {
|
||||
// 2. 'models.form.gpuPerReplica.tips': 'Enter a custom number',
|
||||
// 3. 'models.form.generic_proxy': 'Enable Generic Proxy',
|
||||
// 4. 'models.form.generic_proxy.tips': 'Enable Generic Proxy',
|
||||
// 5. 'models.form.generic_proxy.button': 'Generic Proxy'
|
||||
// 5. 'models.form.generic_proxy.button': 'Generic Proxy',
|
||||
// 6. 'models.accessControlModal.includeusers': 'Include Users',
|
||||
// ========== End of To-Do List ==========
|
||||
|
||||
@@ -234,5 +234,6 @@ export default {
|
||||
'models.form.gpuPerReplica.tips': '输入自定义数值',
|
||||
'models.form.generic_proxy': '启用通用代理',
|
||||
'models.form.generic_proxy.tips': '启用通用代理',
|
||||
'models.form.generic_proxy.button': '通用代理'
|
||||
'models.form.generic_proxy.button': '通用代理',
|
||||
'models.accessControlModal.includeusers': '显示用户'
|
||||
};
|
||||
|
||||
@@ -86,7 +86,8 @@ export const gpuColorMap: Record<string, string> = {
|
||||
dtk: 'magenta',
|
||||
musa: 'cyan',
|
||||
corex: 'purple',
|
||||
maca: 'geekblue'
|
||||
maca: 'geekblue',
|
||||
neuware: 'gold'
|
||||
};
|
||||
|
||||
export const getGpuColor = (gpuType: string) => {
|
||||
@@ -146,10 +147,22 @@ export const frameworks = [
|
||||
label: 'DTK',
|
||||
value: 'dtk'
|
||||
},
|
||||
{
|
||||
label: 'MACA',
|
||||
value: 'maca'
|
||||
},
|
||||
{
|
||||
label: 'CoreX',
|
||||
value: 'corex'
|
||||
},
|
||||
{
|
||||
label: 'MUSA',
|
||||
value: 'musa'
|
||||
},
|
||||
{
|
||||
label: 'Neuware',
|
||||
value: 'neuware'
|
||||
},
|
||||
{
|
||||
label: 'CPU',
|
||||
value: 'cpu'
|
||||
|
||||
@@ -372,7 +372,7 @@ export async function queryCatalogItemSpec(
|
||||
params: { id: number },
|
||||
options?: any
|
||||
) {
|
||||
return await request<Global.PageResponse<CatalogSpec>>(
|
||||
return request<Global.PageResponse<CatalogSpec>>(
|
||||
`/model-sets/${params.id}/specs`,
|
||||
{
|
||||
method: 'GET',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { modelsExpandKeysAtom } from '@/atoms/models';
|
||||
import { modelsExpandKeysAtom, modelsSessionAtom } from '@/atoms/models';
|
||||
import IconFont from '@/components/icon-font';
|
||||
import { FilterBar } from '@/components/page-tools';
|
||||
import { PageAction } from '@/config';
|
||||
@@ -14,7 +14,7 @@ import _ from 'lodash';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import NoResult from '../_components/no-result';
|
||||
import PageBox from '../_components/page-box';
|
||||
import { createModel, queryCatalogList } from './apis';
|
||||
import { createModel, queryCatalogItemSpec, queryCatalogList } from './apis';
|
||||
import CatalogList from './components/catalog-list';
|
||||
import DelopyBuiltInModal from './components/deploy-builtin-modal';
|
||||
import { modelCategories, modelSourceMap } from './config';
|
||||
@@ -50,6 +50,7 @@ const Catalog: React.FC = () => {
|
||||
source: modelSourceMap.huggingface_value
|
||||
});
|
||||
const [modelsExpandKeys, setModelsExpandKeys] = useAtom(modelsExpandKeysAtom);
|
||||
const [, setModelsSession] = useAtom(modelsSessionAtom);
|
||||
const cacheData = React.useRef<CatalogItemType[]>([]);
|
||||
|
||||
const categoryOptions = [
|
||||
@@ -184,7 +185,14 @@ const Catalog: React.FC = () => {
|
||||
});
|
||||
});
|
||||
|
||||
const handleDeployFromOtherHubs = () => {
|
||||
const handleDeployFromOtherHubs = async () => {
|
||||
try {
|
||||
const id = dataSource.dataList?.[0]?.id;
|
||||
const res: any = await queryCatalogItemSpec({ id });
|
||||
setModelsSession({
|
||||
source: res?.items?.[0]?.source
|
||||
});
|
||||
} catch (error) {}
|
||||
navigate('/models/deployments');
|
||||
};
|
||||
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
import AlertBlockInfo from '@/components/alert-info/block';
|
||||
import TransferInner from '@/pages/_components/transfer';
|
||||
import { queryUsersList } from '@/pages/users/apis';
|
||||
import { DownOutlined } from '@ant-design/icons';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Empty, Form, Radio } from 'antd';
|
||||
import { forwardRef, useEffect, useImperativeHandle, useState } from 'react';
|
||||
import { Checkbox, Dropdown, DropdownProps, Empty, Form, Radio } from 'antd';
|
||||
import {
|
||||
forwardRef,
|
||||
useEffect,
|
||||
useImperativeHandle,
|
||||
useMemo,
|
||||
useState
|
||||
} from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { queryModelAccessUserList } from '../../apis';
|
||||
import { AccessControlFormData, ListItem } from '../../config/types';
|
||||
@@ -29,20 +36,42 @@ const AccessControlForm = forwardRef((props: AccessControlFormProps, ref) => {
|
||||
const accessPolicy = Form.useWatch('access_policy', form);
|
||||
const [targetKeys, setTargetKeys] = useState<TransferKey[]>([]);
|
||||
const [totalPages, setTotalPages] = useState(0);
|
||||
const [userList, setUserList] = useState<{ title: string; key: number }[]>(
|
||||
[]
|
||||
);
|
||||
const [userList, setUserList] = useState<
|
||||
{ title: string; key: number; is_admin: boolean; is_active: boolean }[]
|
||||
>([]);
|
||||
const [open, setOpen] = useState(false);
|
||||
const [filterInUsers, setFilterInUsers] = useState<Set<string>>(new Set());
|
||||
const [queryParams, setQueryParams] = useState<Global.SearchParams>({
|
||||
page: -1
|
||||
});
|
||||
|
||||
const dataList = useMemo(() => {
|
||||
if (filterInUsers.size === 0) {
|
||||
return userList.filter((user) => {
|
||||
return !user.is_admin && user.is_active;
|
||||
});
|
||||
}
|
||||
return userList.filter((user) => {
|
||||
const isAdmin = user.is_admin;
|
||||
const isActive = user.is_active;
|
||||
if (!filterInUsers.has('admin') && isAdmin) {
|
||||
return false;
|
||||
}
|
||||
if (!filterInUsers.has('inactive') && !isActive) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}, [userList, filterInUsers]);
|
||||
|
||||
const getUserList = async (query: Global.SearchParams) => {
|
||||
try {
|
||||
const res = await queryUsersList(query);
|
||||
const options = res.items.map((item) => ({
|
||||
title: item.username,
|
||||
key: item.id,
|
||||
is_admin: item.is_admin
|
||||
is_admin: item.is_admin as boolean,
|
||||
is_active: item.is_active as boolean
|
||||
}));
|
||||
setTotalPages(res.pagination.totalPage);
|
||||
setUserList(options);
|
||||
@@ -65,6 +94,30 @@ const AccessControlForm = forwardRef((props: AccessControlFormProps, ref) => {
|
||||
console.log('search:', dir, value);
|
||||
};
|
||||
|
||||
const handleCheck = (e: any, type: string) => {
|
||||
const newSet = new Set(filterInUsers);
|
||||
if (e.target.checked) {
|
||||
newSet.add(type);
|
||||
} else {
|
||||
newSet.delete(type);
|
||||
}
|
||||
setFilterInUsers(newSet);
|
||||
};
|
||||
|
||||
const handleOpenChange: DropdownProps['onOpenChange'] = (nextOpen, info) => {
|
||||
if (info.source === 'trigger' || nextOpen) {
|
||||
setOpen(nextOpen);
|
||||
}
|
||||
};
|
||||
|
||||
const handleFilterChange = (e: any) => {
|
||||
if (e.target.checked) {
|
||||
setFilterInUsers(new Set(['admin', 'inactive']));
|
||||
} else {
|
||||
setFilterInUsers(new Set());
|
||||
}
|
||||
};
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
submit: () => {
|
||||
form.submit();
|
||||
@@ -97,6 +150,51 @@ const AccessControlForm = forwardRef((props: AccessControlFormProps, ref) => {
|
||||
getUserList(queryParams);
|
||||
}, [currentData?.id]);
|
||||
|
||||
const renderFilterDropdown = () => {
|
||||
return (
|
||||
<Dropdown
|
||||
open={open}
|
||||
onOpenChange={handleOpenChange}
|
||||
key="filter-dropdown"
|
||||
menu={{
|
||||
items: [
|
||||
{
|
||||
label: (
|
||||
<Checkbox
|
||||
checked={filterInUsers.has('admin')}
|
||||
onChange={(e: any) => handleCheck(e, 'admin')}
|
||||
>
|
||||
{intl.formatMessage({ id: 'models.table.admin' })}
|
||||
</Checkbox>
|
||||
),
|
||||
key: '0'
|
||||
},
|
||||
{
|
||||
label: (
|
||||
<Checkbox
|
||||
checked={filterInUsers.has('inactive')}
|
||||
onChange={(e: any) => handleCheck(e, 'inactive')}
|
||||
>
|
||||
{intl.formatMessage({ id: 'users.status.deactivate' })}
|
||||
</Checkbox>
|
||||
),
|
||||
key: '1'
|
||||
}
|
||||
]
|
||||
}}
|
||||
>
|
||||
<span>
|
||||
<span className="m-r-8" style={{ cursor: 'default' }}>
|
||||
{intl.formatMessage({
|
||||
id: 'models.accessControlModal.includeusers'
|
||||
})}
|
||||
</span>
|
||||
<DownOutlined />
|
||||
</span>
|
||||
</Dropdown>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form
|
||||
form={form}
|
||||
@@ -149,11 +247,11 @@ const AccessControlForm = forwardRef((props: AccessControlFormProps, ref) => {
|
||||
</Label>
|
||||
<Form.Item<AccessControlFormData> name="users">
|
||||
<TransferInner
|
||||
dataSource={userList}
|
||||
dataSource={dataList}
|
||||
targetKeys={targetKeys}
|
||||
pagination={false}
|
||||
titles={[
|
||||
intl.formatMessage({ id: 'models.table.users.all' }),
|
||||
renderFilterDropdown(),
|
||||
intl.formatMessage({
|
||||
id: 'models.table.users.selected'
|
||||
})
|
||||
@@ -188,9 +286,11 @@ const AccessControlForm = forwardRef((props: AccessControlFormProps, ref) => {
|
||||
<span className="flex-center gap-4">
|
||||
<span>{item.title}</span>
|
||||
<span className="text-tertiary">
|
||||
{item.is_admin
|
||||
? `[${intl.formatMessage({ id: 'models.table.admin' })}]`
|
||||
: ''}
|
||||
{!item.is_active
|
||||
? `[${intl.formatMessage({ id: 'users.status.inactive' })}]`
|
||||
: item.is_admin
|
||||
? `[${intl.formatMessage({ id: 'models.table.admin' })}]`
|
||||
: ''}
|
||||
</span>
|
||||
</span>
|
||||
)}
|
||||
|
||||
@@ -9,7 +9,7 @@ import AccessControlForm from './form';
|
||||
|
||||
const AccessControlModal: React.FC<
|
||||
Global.ScrollerModalProps<ListItem, AccessControlFormData>
|
||||
> = ({ open, title, currentData, action, onOk, onCancel }) => {
|
||||
> = ({ open, title, currentData, action, onCancel }) => {
|
||||
const intl = useIntl();
|
||||
const form = useRef<any>(null);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { modelsExpandKeysAtom } from '@/atoms/models';
|
||||
import { modelsExpandKeysAtom, modelsSessionAtom } from '@/atoms/models';
|
||||
import DeleteModal from '@/components/delete-modal';
|
||||
import DropDownActions from '@/components/drop-down-actions';
|
||||
import DropdownButtons from '@/components/drop-down-buttons';
|
||||
@@ -137,6 +137,7 @@ const Models: React.FC<ModelsProps> = ({
|
||||
isGGUF: false
|
||||
});
|
||||
const [expandAtom, setExpandAtom] = useAtom(modelsExpandKeysAtom);
|
||||
const [modelsSession, setModelsSession] = useAtom(modelsSessionAtom);
|
||||
const intl = useIntl();
|
||||
const navigate = useNavigate();
|
||||
const rowSelection = useTableRowSelection();
|
||||
@@ -591,7 +592,16 @@ const Models: React.FC<ModelsProps> = ({
|
||||
});
|
||||
};
|
||||
|
||||
const handleSubmitAccessControl = (data: any) => {};
|
||||
useEffect(() => {
|
||||
if (modelsSession.source && loadend) {
|
||||
handleClickDropdown({
|
||||
key: modelsSession.source
|
||||
});
|
||||
}
|
||||
return () => {
|
||||
setModelsSession({});
|
||||
};
|
||||
}, [loadend]);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -774,7 +784,6 @@ const Models: React.FC<ModelsProps> = ({
|
||||
></APIAccessInfoModal>
|
||||
<AccessControlModal
|
||||
onCancel={handleCancelAccessControl}
|
||||
onOk={handleSubmitAccessControl}
|
||||
title={openAccessControlModal.title}
|
||||
open={openAccessControlModal.open}
|
||||
currentData={openAccessControlModal.currentData}
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
align-items: center;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: var(--ant-border-radius);
|
||||
overflow: hidden;
|
||||
|
||||
img {
|
||||
height: 32px;
|
||||
|
||||
@@ -5,7 +5,6 @@ import { Form } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import React, {
|
||||
forwardRef,
|
||||
memo,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useId,
|
||||
@@ -194,4 +193,4 @@ const ParamsSettings: React.FC<ParamsSettingsProps> = forwardRef(
|
||||
}
|
||||
);
|
||||
|
||||
export default memo(ParamsSettings);
|
||||
export default ParamsSettings;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { setRouteCache } from '@/atoms/route-cache';
|
||||
import AlertInfo from '@/components/alert-info';
|
||||
import IconFont from '@/components/icon-font';
|
||||
import AutoComplete from '@/components/seal-form/auto-complete';
|
||||
import SealSelect from '@/components/seal-form/seal-select';
|
||||
import SpeechContent from '@/components/speech-content';
|
||||
import routeCachekey from '@/config/route-cachekey';
|
||||
@@ -274,17 +275,20 @@ const GroundTTS: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
|
||||
const renderExtra = useMemo(() => {
|
||||
return paramsConfig.map((item: ParamsSchema) => {
|
||||
const comProps = {
|
||||
...item.attrs,
|
||||
options: item.name === 'voice' ? voiceList : item.options,
|
||||
label: item.label.isLocalized
|
||||
? intl.formatMessage({ id: item.label.text })
|
||||
: item.label.text
|
||||
};
|
||||
return (
|
||||
<Form.Item name={item.name} rules={item.rules} key={item.name}>
|
||||
<SealSelect
|
||||
{...item.attrs}
|
||||
options={item.name === 'voice' ? voiceList : item.options}
|
||||
label={
|
||||
item.label.isLocalized
|
||||
? intl.formatMessage({ id: item.label.text })
|
||||
: item.label.text
|
||||
}
|
||||
></SealSelect>
|
||||
{item.type === 'AutoComplete' ? (
|
||||
<AutoComplete {...comProps} />
|
||||
) : (
|
||||
<SealSelect {...comProps}></SealSelect>
|
||||
)}
|
||||
</Form.Item>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -32,7 +32,7 @@ export const imageSizeOptions: {
|
||||
|
||||
export const TTSParamsConfig: ParamsSchema[] = [
|
||||
{
|
||||
type: 'Select',
|
||||
type: 'AutoComplete',
|
||||
name: 'voice',
|
||||
options: [],
|
||||
label: {
|
||||
@@ -41,7 +41,7 @@ export const TTSParamsConfig: ParamsSchema[] = [
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
required: false,
|
||||
message: 'Voice is required'
|
||||
}
|
||||
]
|
||||
|
||||
@@ -38,13 +38,13 @@ export interface MessageItem {
|
||||
type SchemaType =
|
||||
| 'Input'
|
||||
| 'InputNumber'
|
||||
| 'Textarea'
|
||||
| 'TextArea'
|
||||
| 'Select'
|
||||
| 'Slider'
|
||||
| 'TextArea'
|
||||
| 'Checkbox'
|
||||
| 'Textarea'
|
||||
| 'Switch';
|
||||
| 'Checkbox'
|
||||
| 'Switch'
|
||||
| 'AutoComplete';
|
||||
|
||||
export interface ParamsSchema {
|
||||
type: SchemaType;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
export const GPUDriverMap = {
|
||||
NVIDIA: 'cuda',
|
||||
AMD: 'rocm',
|
||||
ASCEND: 'npu',
|
||||
HYGON: 'dcu',
|
||||
ASCEND: 'cann',
|
||||
HYGON: 'dtk',
|
||||
MOORE_THREADS: 'musa',
|
||||
ILUVATAR: 'corex',
|
||||
CAMBRICON: 'cambricon',
|
||||
METAX: 'metax'
|
||||
CAMBRICON: 'neuware',
|
||||
METAX: 'maca'
|
||||
};
|
||||
|
||||
const ManufacturerMap = {
|
||||
@@ -45,7 +45,7 @@ export const GPUsConfigs: Record<
|
||||
[GPUDriverMap.HYGON]: {
|
||||
label: ManufacturerMap[GPUDriverMap.HYGON],
|
||||
value: GPUDriverMap.HYGON,
|
||||
runtime: 'dcu', // TODO: confirm runtime name
|
||||
runtime: '', // TODO: confirm runtime name
|
||||
driver: 'hy-smi'
|
||||
},
|
||||
[GPUDriverMap.MOORE_THREADS]: {
|
||||
@@ -57,7 +57,7 @@ export const GPUsConfigs: Record<
|
||||
[GPUDriverMap.ILUVATAR]: {
|
||||
label: ManufacturerMap[GPUDriverMap.ILUVATAR],
|
||||
value: GPUDriverMap.ILUVATAR,
|
||||
runtime: 'corex', // TODO: confirm runtime name
|
||||
runtime: '', // TODO: confirm runtime name
|
||||
driver: 'ixsmi'
|
||||
},
|
||||
[GPUDriverMap.CAMBRICON]: {
|
||||
|
||||
@@ -68,15 +68,6 @@ export const addWorkerGuide: Record<string, any> = {
|
||||
}
|
||||
};
|
||||
|
||||
export const containerInstallOptions = [
|
||||
{ label: 'NVIDIA CUDA', value: 'cuda' },
|
||||
{ label: 'AMD ROCm', value: 'rocm' },
|
||||
{ label: 'Ascend CANN', value: 'npu' },
|
||||
{ label: 'Hygon DTK', value: 'dcu' },
|
||||
{ label: 'Moore Threads MUSA', value: 'musa' },
|
||||
{ label: 'Iluvatar Corex', value: 'corex' }
|
||||
];
|
||||
|
||||
export const ModelfileStateMap = {
|
||||
Error: 'error',
|
||||
Downloading: 'downloading',
|
||||
|
||||
Reference in New Issue
Block a user